#include #include #include #include "toml.h" #include "pcap_io.h" #include "marsio_io.h" #include "log_internal.h" #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__) struct packet_io { struct packet_io_config *cfg; 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); 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); 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); }; static struct packet_io_config *packet_io_config_new(const char *toml_file) { int ret = -1; const char *ptr; char *ptr_mode = NULL; char *ptr_pcap_path = NULL; 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; struct packet_io_config *cfg = (struct packet_io_config *)calloc(1, sizeof(struct packet_io_config)); if (cfg == NULL) { return NULL; } fp = fopen(toml_file, "r"); if (fp == NULL) { PACKET_IO_LOG_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) { PACKET_IO_LOG_ERROR("config file %s parse failed, %s", toml_file, errbuf); goto error_out; } table = toml_table_in(root, "packet_io"); if (table == NULL) { PACKET_IO_LOG_ERROR("config file %s missing packet_io", toml_file); goto error_out; } ptr = toml_raw_in(table, "mode"); if (ptr == NULL || toml_rtos(ptr, &ptr_mode) != 0) { 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); goto error_out; } if (cfg->mode == PACKET_IO_PCAPFILE || cfg->mode == PACKET_IO_PCAPLIST) { ptr = toml_raw_in(table, "pcap_path"); if (ptr == NULL || toml_rtos(ptr, &ptr_pcap_path) != 0) { PACKET_IO_LOG_ERROR("config file missing packet_io.pcap_path"); goto error_out; } strcpy(cfg->pcap_path, ptr_pcap_path); } else { ptr = toml_raw_in(table, "app_symbol"); if (ptr == NULL || toml_rtos(ptr, &ptr_app_symbol) != 0) { PACKET_IO_LOG_ERROR("config file missing packet_io.app_symbol"); goto error_out; } 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); } ptr = toml_raw_in(table, "nr_worker_thread"); if (ptr == NULL) { PACKET_IO_LOG_ERROR("config file missing packet_io.nr_worker_thread"); goto error_out; } cfg->nr_worker_thread = atoi(ptr); if (cfg->nr_worker_thread == 0 || cfg->nr_worker_thread > MAX_THREAD_NUM) { 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; } mask = toml_array_in(table, "cpu_mask"); if (mask == NULL) { PACKET_IO_LOG_ERROR("config file missing packet_io.cpu_mask"); goto error_out; } for (uint16_t i = 0; i < cfg->nr_worker_thread; i++) { 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); } ptr = toml_raw_in(table, "idle_yield_interval_ms"); if (ptr == NULL) { PACKET_IO_LOG_ERROR("config file missing packet_io.idle_yield_interval_ms"); goto error_out; } cfg->idle_yield_interval_ms = atoll(ptr); if (cfg->idle_yield_interval_ms > 60000) { 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; } ret = 0; error_out: if (ptr_mode) { free(ptr_mode); } if (ptr_pcap_path) { free(ptr_pcap_path); } if (ptr_app_symbol) { free(ptr_app_symbol); } if (ptr_dev_symbol) { free(ptr_dev_symbol); } if (root) { toml_free(root); } if (fp) { fclose(fp); } if (ret == -1) { free(cfg); return NULL; } else { return cfg; } } static void packet_io_config_free(struct packet_io_config *cfg) { if (cfg) { free(cfg); cfg = NULL; } } static void packet_io_config_print(const struct packet_io_config *cfg) { if (cfg) { 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++) { PACKET_IO_LOG_INFO("packet_io.cpu_mask[%03d] : %d", i, cfg->cpu_mask[i]); } PACKET_IO_LOG_INFO("packet_io.idle_yield_interval_ms : %lu", cfg->idle_yield_interval_ms); } } struct packet_io *packet_io_new(const char *toml_file) { struct packet_io *pkt_io = (struct packet_io *)calloc(1, sizeof(struct packet_io)); if (pkt_io == NULL) { return NULL; } 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) { 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; pkt_io->ingress_func = marsio_io_ingress; pkt_io->egress_func = marsio_io_egress; pkt_io->drop_func = marsio_io_drop; pkt_io->yield_func = marsio_io_yield; pkt_io->stat_func = marsio_io_stat; } else { 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; pkt_io->ingress_func = pcap_io_ingress; pkt_io->egress_func = pcap_io_egress; pkt_io->drop_func = pcap_io_drop; pkt_io->yield_func = pcap_io_yield; pkt_io->stat_func = pcap_io_stat; } pkt_io->handle = pkt_io->new_func(pkt_io->cfg); if (pkt_io->handle == NULL) { packet_io_free(pkt_io); return NULL; } return pkt_io; } void packet_io_free(struct packet_io *pkt_io) { if (pkt_io) { if (pkt_io->handle) { pkt_io->free_func(pkt_io->handle); } if (pkt_io->cfg) { packet_io_config_free(pkt_io->cfg); } free(pkt_io); pkt_io = NULL; } } 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); } uint16_t packet_io_ingress(struct packet_io *pkt_io, uint16_t thr_idx, struct packet *pkts, uint16_t nr_pkts) { return pkt_io->ingress_func(pkt_io->handle, thr_idx, pkts, nr_pkts); } void packet_io_egress(struct packet_io *pkt_io, uint16_t thr_idx, struct packet *pkts, uint16_t nr_pkts) { pkt_io->egress_func(pkt_io->handle, thr_idx, pkts, nr_pkts); } 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); }