/* ********************************************************************************************** * File: packet_io_internal.cpp * Description: * Authors: Liu WenTan * Date: 2022-07-15 * Copyright: (c) 2018-2022 Geedge Networks, Inc. All rights reserved. *********************************************************************************************** */ #include #include "logger.h" #include "utils.h" #include "util_errors.h" #include "packet_io.h" #include "packet_io_util.h" #include "packet_io_internal.h" #include "toml/toml.h" #include "./pcap_live_mode/pio_pcap_live.h" #include "./pcap_file_mode/pio_pcap_file.h" #include "./marsio_mode/pio_marsio.h" struct packet_io_config g_packet_io_config; struct pio_device_operations pio_device_ops_array[PACKET_IO_RUN_MODE_MAX] = { { .open = pio_pcap_file_device_open, .close = pio_pcap_file_device_close, .recv = pio_pcap_file_device_receive, .send = pio_pcap_file_device_send, .pkt_free = pio_pcap_file_device_pkt_free, .buff_ctrlzone = pio_pcap_file_device_buff_ctrlzone, .buff_mtod = pio_pcap_file_device_buff_mtod, }, { .open = pio_pcap_live_device_open, .close = pio_pcap_live_device_close, .recv = pio_pcap_live_device_receive, .send = pio_pcap_live_device_send, .pkt_free = pio_pcap_live_device_pkt_free, .buff_ctrlzone = pio_pcap_live_device_buff_ctrlzone, .buff_mtod = pio_pcap_live_device_buff_mtod, }, { .open = pio_marsio_device_open, .close = pio_marsio_device_close, .recv = pio_marsio_device_receive, .send = pio_marsio_device_send, .pkt_free = pio_marsio_device_pkt_free, .buff_ctrlzone = pio_marsio_device_buff_ctrlzone, .buff_mtod = pio_marsio_device_buff_mtod, } }; struct pio_instance_operations pio_instance_ops_array[PACKET_IO_RUN_MODE_MAX] = { { .create = pio_pcap_file_instance_create, .destroy = pio_pcap_file_instance_destroy, }, { .create = pio_pcap_live_instance_create, .destroy = pio_pcap_live_instance_destroy, }, { .create = pio_marsio_instance_create, .destroy = pio_marsio_instance_destroy, } }; struct packet_io_instance * packet_io_instance_create(const char *inst_name, const enum packet_io_run_mode mode) { if (nullptr == inst_name || mode < PACKET_IO_RUN_MODE_PCAP_FILE || mode >= PACKET_IO_RUN_MODE_MAX) { return nullptr; } struct packet_io_instance *pio_instance = CALLOC(struct packet_io_instance, 1); if (nullptr == pio_instance) { log_error(ST_ERR_MEM_ALLOC, "packet_io instance alloc failed."); return nullptr; } ssize_t ret = strncpy_safe(pio_instance->inst_name, inst_name, sizeof(pio_instance->inst_name)); if (ret < 0) { log_error(ST_ERR_STR_COPY, "packet_io instance name copy failed."); return nullptr; } TAILQ_INIT(&pio_instance->device_queue_head); pio_instance->mode = mode; pio_instance->inst_ops = &pio_instance_ops_array[mode]; ret = pio_instance->inst_ops->create(pio_instance); if (ret < 0) { log_error(ST_ERR_PIO_INSTANCE, "packet_io instance create failed."); return nullptr; } return pio_instance; } static ssize_t toml_parse_table(toml_table_t *table, const char *string_key, const char *file_name, toml_table_t **out) { *out = toml_table_in(table, string_key); if (nullptr == *out) { log_error(ST_ERR_PIO_CONFIG, "can't find '%s' section in %s", string_key, file_name); return -1; } return 0; } static ssize_t toml_parse_string(toml_table_t *table, const char *string_key, const char *file_name, char *out) { toml_datum_t string_val = toml_string_in(table, string_key); if (!string_val.ok) { log_error(ST_ERR_PIO_CONFIG, "can't find '%s' configuration iterm in %s", string_key, file_name); return -1; } if (strlen(string_val.u.s) <= 0) { log_error(ST_ERR_PIO_CONFIG, "invalid value for '%s' configuration item in %s", string_key, file_name); FREE(string_val.u.s); return -1; } strncpy_safe(out, string_val.u.s, strlen(string_val.u.s) + 1); FREE(string_val.u.s); return 0; } static ssize_t toml_parse_int(toml_table_t *table, const char *int_key, const char *file_name, int *out) { toml_datum_t int_val = toml_int_in(table, int_key); if (!int_val.ok) { log_error(ST_ERR_PIO_CONFIG, "can't find '%s' configuration iterm in %s", int_key, file_name); return -1; } *out = int_val.u.i; return 0; } enum packet_io_run_mode pio_run_mode_str2int(const char *mode_str) { enum packet_io_run_mode mode_int = PACKET_IO_RUN_MODE_MAX; if (strncmp("PCAP_FILE_MODE", mode_str, strlen(mode_str)) == 0) { mode_int = PACKET_IO_RUN_MODE_PCAP_FILE; } else if (strncmp("PCAP_LIVE_MODE", mode_str, strlen(mode_str)) == 0) { mode_int = PACKET_IO_RUN_MODE_PCAP_LIVE; } else if (strncmp("MARSIO_MODE", mode_str, strlen(mode_str)) == 0) { mode_int = PACKET_IO_RUN_MODE_MARSIO; } else { log_error(ST_ERR_RUN_MODE, "unknown run mode '%s'", mode_str); } return mode_int; } static ssize_t toml_parse_pcap_file_mode(toml_table_t *tab, struct packet_io_config *config, const char *file_name) { if (toml_parse_string(tab, "PCAP_FILE_PATH", file_name, config->pcap.path) < 0) { log_error(ST_ERR_PIO_CONFIG, "can't parse 'PCAP_FILE_PATH' config iterm in 'PACKET_IO' section of %s", file_name); return -1; } if (toml_parse_int(tab, "DELETE_WHEN_DONE", file_name, &config->pcap.should_delete) < 0) { log_notice("can't parse 'DELETE_WHEN_DONE' config iterm in 'PACKET_IO' section of %s", file_name); } if (toml_parse_string(tab, "BPF_FILTER", file_name, config->pcap.bpf_string) < 0) { log_notice("can't parse 'BPF_FILTER' config iterm in 'PACKET_IO' section of %s", file_name); } return 0; } static ssize_t toml_parse_pcap_live_mode(toml_table_t *tab, struct packet_io_config *config, const char *file_name) { toml_array_t *interface_array = nullptr; toml_datum_t interface_str; interface_array = toml_array_in(tab, "INTERFACE"); if (nullptr == interface_array) { log_error(ST_ERR_PIO_CONFIG, "can't find 'INTERFACE' config iterm in 'PACKET_IO' section of %s", file_name); return -1; } for (ssize_t i = 0; i < toml_array_nelem(interface_array); i++) { interface_str = toml_string_at(interface_array, i); if (!interface_str.ok) { log_error(ST_ERR_PIO_CONFIG, "can't parse 'INTERFACE' config iterm in 'PACKET_IO' section of %s", file_name); return -1; } strncpy_safe(config->common.dev_name[i], interface_str.u.s, sizeof(config->common.dev_name[i])); config->common.dev_cnt++; } if (toml_parse_int(tab, "SNAP_LEN", file_name, &config->pcap.snaplen) < 0) { log_notice("can't parse 'SNAP_LEN' config iterm in 'PACKET_IO' section of %s", file_name); } if (toml_parse_int(tab, "PROMISC", file_name, &config->pcap.promisc) < 0) { log_notice("can't parse 'PROMISC' config iterm in 'PACKET_IO' section of %s", file_name); } if (toml_parse_string(tab, "BPF_FILTER", file_name, config->pcap.bpf_string) < 0) { log_notice("can't parse 'BPF_FILTER' config iterm in 'PACKET_IO' section of %s", file_name); } return 0; } static ssize_t toml_parse_marsio_mode(toml_table_t *tab, struct packet_io_config *config, const char *file_name) { toml_array_t *interface_array = nullptr; toml_datum_t interface_str; interface_array = toml_array_in(tab, "INTERFACE"); if (nullptr == interface_array) { log_error(ST_ERR_PIO_CONFIG, "can't find 'INTERFACE' config iterm in 'PACKET_IO' section of %s", file_name); return -1; } for (int i = 0; i < toml_array_nelem(interface_array); i++) { interface_str = toml_string_at(interface_array, i); if (!interface_str.ok) { log_error(ST_ERR_PIO_CONFIG, "can't parse 'INTERFACE' config iterm in 'PACKET_IO' section of %s", file_name); return -1; } strncpy_safe(config->common.dev_name[i], interface_str.u.s, sizeof(config->common.dev_name[i])); config->common.dev_cnt++; } return 0; } static ssize_t toml_parse_packet_io_section(toml_table_t *root, struct packet_io_config *config, const char *file_name) { toml_table_t *packet_io_section = nullptr; if (toml_parse_table(root, "PACKET_IO", file_name, &packet_io_section) < 0) { return -1; } char run_mode[STR_MAX_LEN] = {0}; if (toml_parse_string(packet_io_section, "RUN_MODE", file_name, run_mode) < 0) { return -1; } config->common.mode = pio_run_mode_str2int(run_mode); if (config->common.mode == PACKET_IO_RUN_MODE_MAX) { return -1; } if (toml_parse_int(packet_io_section, "WORKER_THREAD_NUM", file_name, &config->common.thread_num) < 0) { return -1; } if (config->common.mode == PACKET_IO_RUN_MODE_PCAP_FILE) { if (toml_parse_pcap_file_mode(packet_io_section, config, file_name) < 0) { return -1; } } else if (config->common.mode == PACKET_IO_RUN_MODE_PCAP_LIVE) { if (toml_parse_pcap_live_mode(packet_io_section, config, file_name) < 0) { return -1; } } else { if (toml_parse_marsio_mode(packet_io_section, config, file_name) < 0) { return -1; } } return 0; } ssize_t packet_io_config_parse(struct packet_io_config *config, const char *file_name) { char errbuf[BUFSIZ] = {0}; FILE *fp = fopen(file_name, "r"); if (nullptr == fp) { log_error(ST_ERR_FOPEN, "open packet_io config file failed."); return -1; } toml_table_t *root = nullptr; root = toml_parse_file(fp, errbuf, sizeof(errbuf)); if (nullptr == root) { goto err; } if (toml_parse_packet_io_section(root, config, file_name) < 0) { goto err; } toml_free(root); fclose(fp); log_info("packet_io config file '%s' parse success", file_name); return 0; err: if (root) { toml_free(root); } if (fp) { fclose(fp); fp = nullptr; } return -1; } struct packet_io_device * packet_io_device_open(struct packet_io_instance *pinst, const char *dev_name, size_t nr_rxq, size_t nr_txq) { if (nullptr == pinst || nullptr == dev_name) { return nullptr; } struct packet_io_device *pdev = CALLOC(struct packet_io_device, 1); if (nullptr == pdev) { log_error(ST_ERR_MEM_ALLOC, "packet_io device alloc failed."); return nullptr; } ssize_t ret = strncpy_safe(pdev->dev_name, dev_name, sizeof(pdev->dev_name)); if (ret < 0) { log_error(ST_ERR_STR_COPY, "packet_io device name copy failed."); return nullptr; } pdev->rxq_num = nr_rxq; pdev->txq_num = nr_txq; pdev->ppio_inst = pinst; pdev->dev_ops = &pio_device_ops_array[pinst->mode]; TAILQ_INSERT_TAIL(&pinst->device_queue_head, pdev, next); pinst->dev_cnt++; ret = pdev->dev_ops->open(pdev); if (ret < 0) { log_error(ST_ERR_PIO_DEVICE, "packet_io device open failed."); return nullptr; } return pdev; } void packet_io_device_close(struct packet_io_device *pdev) { ssize_t ret = pdev->dev_ops->close(pdev); if (ret < 0) { log_error(ST_ERR_PIO_DEVICE, "packet_io device close failed."); return; } struct packet_io_device *node = nullptr; struct packet_io_device *next_node = nullptr; for (node = TAILQ_FIRST(&pdev->ppio_inst->device_queue_head); node != nullptr; node = next_node) { next_node = TAILQ_NEXT(node, next); if (node == pdev) { pdev->ppio_inst->dev_cnt--; /* Remove the item from the tail queue. */ TAILQ_REMOVE(&pdev->ppio_inst->device_queue_head, node, next); /* Free the item as we don't need it anymore. */ FREE(node); break; } } } struct packet_io_instance * packet_io_init(const char *instance_name, const char *file_name, struct packet_io_device *devices[], size_t *dev_num) { /* parse config file */ memset(&g_packet_io_config, 0, sizeof(g_packet_io_config)); ssize_t ret = packet_io_config_parse(&g_packet_io_config, file_name); if (ret < 0) { log_error(ST_ERR_PIO_CONFIG, "packet_io config parse failed."); return nullptr; } struct packet_io_instance *ppio_inst = packet_io_instance_create("stellar", g_packet_io_config.common.mode); if (nullptr == ppio_inst) { log_error(ST_ERR_PIO_INSTANCE, "packet_io instance init failed."); return nullptr; } size_t thread_num = g_packet_io_config.common.thread_num; if (g_packet_io_config.common.mode == PACKET_IO_RUN_MODE_PCAP_FILE) { devices[0] = packet_io_device_open(ppio_inst, g_packet_io_config.pcap.path, thread_num, thread_num); if (nullptr == devices[0]) { log_error(ST_ERR_PIO_DEVICE, "packet_io device '%s' open failed.", g_packet_io_config.pcap.path); return nullptr; } *dev_num = 1; } else { *dev_num = g_packet_io_config.common.dev_cnt; for (size_t i = 0; i < *dev_num; i++) { devices[i] = packet_io_device_open(ppio_inst, g_packet_io_config.common.dev_name[i], thread_num, thread_num); if (nullptr == devices[i]) { log_error(ST_ERR_PIO_DEVICE, "packet_io device '%s' open failed.", g_packet_io_config.common.dev_name[i]); return nullptr; } } } return ppio_inst; } void packet_io_fini(struct packet_io_instance *pinst) { packet_io_instance_destroy(pinst); } void packet_io_instance_destroy(struct packet_io_instance *pinst) { if (nullptr == pinst) { return; } pinst->inst_ops->destroy(pinst); FREE(pinst); } ssize_t packet_io_device_rx(struct packet_io_device *pdev, uint32_t rxq_id, struct stellar_packet **pkts, size_t nr_pkts) { return pdev->dev_ops->recv(pdev, rxq_id, pkts, nr_pkts); } ssize_t packet_io_device_tx(struct packet_io_device *pdev, uint32_t txq_id, struct stellar_packet **pkts, size_t nr_pkts) { return pdev->dev_ops->send(pdev, txq_id, pkts, nr_pkts); } void packet_io_pkts_free(struct packet_io_device *pdev, uint32_t qid, struct stellar_packet **pkts, size_t nr_pkts) { return pdev->dev_ops->pkt_free(pdev, qid, pkts, nr_pkts); } char *get_stellar_packet_ctrlzone(struct stellar_packet *p, size_t *ctrlzone_len) { return pio_device_ops_array[g_packet_io_config.common.mode].buff_ctrlzone(p, ctrlzone_len); } char *get_stellar_packet_data(struct stellar_packet *p, size_t *data_len) { return pio_device_ops_array[g_packet_io_config.common.mode].buff_mtod(p, data_len); }