From 90b359ed40368f552ae251daaa82a75ff2b86f3e Mon Sep 17 00:00:00 2001 From: liuwentan Date: Thu, 18 Aug 2022 16:26:00 +0800 Subject: [PATCH] [PACKET_IO]format api style --- CMakeLists.txt | 4 + sdk/include/packet.h | 15 +- sdk/include/util_errors.h | 1 + src/app.toml | 37 +- src/common/global_var.cpp | 13 - src/common/global_var.h | 94 ---- src/common/time_helper.cpp | 2 +- src/common/time_helper.h | 3 +- src/main.cpp | 5 +- src/packet_io/CMakeLists.txt | 3 +- src/packet_io/marsio_mode/pio_marsio.cpp | 116 +++-- src/packet_io/marsio_mode/pio_marsio.h | 22 +- src/packet_io/packet_io.cpp | 203 -------- src/packet_io/packet_io.h | 162 ++---- src/packet_io/packet_io_internal.cpp | 461 ++++++++++++++++++ src/packet_io/packet_io_internal.h | 155 ++++++ src/packet_io/packet_io_util.cpp | 9 +- src/packet_io/packet_io_util.h | 6 +- .../pcap_file_mode/pio_pcap_file.cpp | 133 ++--- src/packet_io/pcap_file_mode/pio_pcap_file.h | 25 +- .../pcap_live_mode/pio_pcap_live.cpp | 100 ++-- src/packet_io/pcap_live_mode/pio_pcap_live.h | 23 +- src/packet_io/test/CMakeLists.txt | 1 + src/packet_io/test/gtest_packet_io.cpp | 270 +++++++++- src/packet_io/test/test-64.pcapng | Bin 0 -> 25668 bytes 25 files changed, 1171 insertions(+), 692 deletions(-) delete mode 100644 src/common/global_var.cpp delete mode 100644 src/common/global_var.h delete mode 100644 src/packet_io/packet_io.cpp create mode 100644 src/packet_io/packet_io_internal.cpp create mode 100644 src/packet_io/packet_io_internal.h create mode 100644 src/packet_io/test/test-64.pcapng diff --git a/CMakeLists.txt b/CMakeLists.txt index f11277d..2549c33 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,6 +9,10 @@ add_definitions(-D_GNU_SOURCE) set(CMAKE_CXX_STANDARD 11) set(CMAKE_C_STANDARD 11) +SET(CMAKE_BUILD_TYPE "Debug") +SET(CMAKE_CXX_FLAGS_DEBUG "$ENV{CXXFLAGS} -O0 -Wall -g -ggdb") +SET(CMAKE_CXX_FLAGS_RELEASE "$ENV{CXXFLAGS} -O3 -Wall") + if(NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE RelWithDebInfo) endif() diff --git a/sdk/include/packet.h b/sdk/include/packet.h index 8ffe7c2..3b64d74 100644 --- a/sdk/include/packet.h +++ b/sdk/include/packet.h @@ -1,3 +1,16 @@ #pragma once -struct stellar_packet; \ No newline at end of file +#include + +struct stellar_packet; + +/** + * @brief get stellar_packet's ctrlzone + * @note ctrlzone's memory is 64 bytes, do not exceed it + */ +char *get_stellar_packet_ctrlzone(struct stellar_packet *p, size_t *ctrlzone_len); + +/** + * @brief get stellar_packet's data pointer + */ +char *get_stellar_packet_data(struct stellar_packet *p, size_t *data_len); \ No newline at end of file diff --git a/sdk/include/util_errors.h b/sdk/include/util_errors.h index 1426a06..53997fa 100644 --- a/sdk/include/util_errors.h +++ b/sdk/include/util_errors.h @@ -39,6 +39,7 @@ typedef enum { ST_ERR_PCAP_SET_PROMISC, ST_ERR_PCAP_SET_TIMEOUT, ST_ERR_PCAP_ACTIVATE_HANDLE, + ST_ERR_PIO_CONFIG, ST_ERR_FOPEN, ST_ERR_BPF, ST_ERR_MAX diff --git a/src/app.toml b/src/app.toml index 83a8f4b..83a1eb4 100644 --- a/src/app.toml +++ b/src/app.toml @@ -1,19 +1,24 @@ -[THREAD] - -thread_num = 1 - [PACKET_IO] -""" -example1: -run_mode = pcap_live -interface = [eth0, eth1] +# example1: +# RUN_MODE="PCAP_LIVE_MODE" +# WORKER_THREAD_NUM=10 # Prompt marsio how many threads to start to receive packets +# INTERFACE=["eth0", "eth1"] +# SNAP_LEN=65535 # default 65535 +# PROMISC=1 # 0(disable) 1(enable), if enable nic promisc mode, default 0(disable) +# BPF_FILTER="port 80 and udp" # default null -example2: -run_mode = marsio -work_thread_num = 10 # Prompt marsio how many threads to start to receive packets -interface = [eth0] +# example2: +# RUN_MODE="MARSIO_MODE" +# WORKER_THREAD_NUM=10 # Prompt marsio how many threads to start to receive packets +# INTERFACE=["eth0", "eth1"] -example3: -run_mode = pcap_file -pcap_file_path = /tmp/pcapfile/001.pcap # if single file, specify dir+filename; if pcapfile directory, specify dir -""" \ No newline at end of file +# example3: +# RUN_MODE="PCAP_FILE_MODE" +# WORKER_THREAD_NUM=10 # Prompt marsio how many threads to start to receive packets +# PCAP_FILE_PATH="/tmp/pcapfile/001.pcap" # if single file, specify dir+filename; if pcapfile directory, specify dir +# DELETE_WHEN_DONE=0 # 0(false) 1(true), default 0, if delete it when the pcapfile is processed +# BPF_FILTER="port 80 and udp" # default null + +RUN_MODE="PCAP_LIVE_MODE" +WORKER_THREAD_NUM=3 # Prompt marsio how many threads to start to receive packets +INTERFACE=["eth0"] \ No newline at end of file diff --git a/src/common/global_var.cpp b/src/common/global_var.cpp deleted file mode 100644 index 4a63b76..0000000 --- a/src/common/global_var.cpp +++ /dev/null @@ -1,13 +0,0 @@ -/* -********************************************************************************************** -* File: global_var.cpp -* Description: -* Authors: Liu WenTan -* Date: 2022-07-15 -* Copyright: (c) 2018-2022 Geedge Networks, Inc. All rights reserved. -*********************************************************************************************** -*/ - -#include "global_var.h" - -struct stellar_engine g_engine_instance; \ No newline at end of file diff --git a/src/common/global_var.h b/src/common/global_var.h deleted file mode 100644 index 5484363..0000000 --- a/src/common/global_var.h +++ /dev/null @@ -1,94 +0,0 @@ -/* -********************************************************************************************** -* File: global_var.h -* Description: global variable and data structure -* Authors: Liu WenTan -* Date: 2022-07-15 -* Copyright: (c) 2018-2022 Geedge Networks, Inc. All rights reserved. -*********************************************************************************************** -*/ - -#ifndef _GLOBAL_VAR_H_ -#define _GLOBAL_VAR_H_ - -#ifdef __cpluscplus -extern "C" -{ -#endif - -#include -#include -#include - -#define DEV_MAX_CNT 64 -#define STR_MAX_LEN 1024 - -enum packet_io_run_mode { - PACKET_IO_RUN_MODE_PCAP_FILE, - PACKET_IO_RUN_MODE_PCAP_LIVE, - PACKET_IO_RUN_MODE_MARSIO, - PACKET_IO_RUN_MODE_MAX, -}; - -struct cpu_config {}; -struct mem_config {}; - -struct system_config { - char instance_name[NAME_MAX]; -}; - -/* store packet_io config */ -struct packet_io_config { - /* packet_io run mode */ - enum packet_io_run_mode mode; - - /* worker thread num */ - uint32_t thread_num; - - /* device name list */ - char dev_name[DEV_MAX_CNT][NAME_MAX]; - - /* device counts */ - uint32_t dev_cnt; - - /* bpf filter string, such as "tcp and port 25"*/ - char bpf_string[STR_MAX_LEN]; - - /* delete after the pcap file is read */ - bool should_delete; - - time_t delay; - - /* snapshot length */ - int snaplen; - - /* promiscuous value */ - int promisc; - - /* marsio ctrlzone id */ - int mr_ctrlzone_id; -}; - -struct lib_config { - const char *libmarsio_path; -}; - -struct stellar_config { - struct cpu_config cpu; - struct mem_config mem; - struct system_config system; - struct packet_io_config packet_io; - struct lib_config lib; -}; - -struct stellar_engine { - struct stellar_config config; -}; - -extern struct stellar_engine g_engine_instance; - -#ifdef __cpluscplus -} -#endif - -#endif /* _GLOBAL_VAR_H_ */ \ No newline at end of file diff --git a/src/common/time_helper.cpp b/src/common/time_helper.cpp index 2545ba7..2eb2399 100644 --- a/src/common/time_helper.cpp +++ b/src/common/time_helper.cpp @@ -21,7 +21,7 @@ void get_current_timespec(struct timespec *tm) } } -int compare_timespec(struct timespec *left, struct timespec *right) +ssize_t compare_timespec(struct timespec *left, struct timespec *right) { if (left->tv_sec < right->tv_sec) { return -1; diff --git a/src/common/time_helper.h b/src/common/time_helper.h index 55e7e60..fd1073a 100644 --- a/src/common/time_helper.h +++ b/src/common/time_helper.h @@ -18,10 +18,11 @@ extern "C" #include #include +#include void get_current_timespec(struct timespec *tm); -int compare_timespec(struct timespec *left, struct timespec *right); +ssize_t compare_timespec(struct timespec *left, struct timespec *right); void copy_timespec(struct timespec *from, struct timespec *to); diff --git a/src/main.cpp b/src/main.cpp index 4b56e52..615e046 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -7,6 +7,8 @@ *********************************************************************************************** */ +#include +#include #include #include #include @@ -15,13 +17,13 @@ #include #include -#include "global_var.h" #include "logger.h" #include "packet_io.h" #include "packet_io_util.h" #include "session_manager.h" #include "plugin_manager.h" #include "http.h" +#include "utils.h" #include "util_errors.h" struct worker_thread_ctx @@ -59,6 +61,7 @@ void *worker_thread_cycle(void *arg) // dispatch to trigger polling event } #endif + } } return nullptr; } diff --git a/src/packet_io/CMakeLists.txt b/src/packet_io/CMakeLists.txt index d84f4ac..bc0f786 100644 --- a/src/packet_io/CMakeLists.txt +++ b/src/packet_io/CMakeLists.txt @@ -1,9 +1,8 @@ add_library(packet_io - ../common/global_var.cpp ../common/time_helper.cpp - packet_io.cpp packet_io_util.cpp + packet_io_internal.cpp pcap_live_mode/pio_pcap_live.cpp pcap_file_mode/pio_pcap_file.cpp marsio_mode/pio_marsio.cpp diff --git a/src/packet_io/marsio_mode/pio_marsio.cpp b/src/packet_io/marsio_mode/pio_marsio.cpp index 8a95266..a867ab2 100644 --- a/src/packet_io/marsio_mode/pio_marsio.cpp +++ b/src/packet_io/marsio_mode/pio_marsio.cpp @@ -11,12 +11,12 @@ #include #include -#include "global_var.h" #include "logger.h" #include "utils.h" #include "util_errors.h" #include "pio_marsio.h" #include "packet_io.h" +#include "packet_io_internal.h" #define MARSIO_BURST_PKT_MAX (256) @@ -28,14 +28,14 @@ static void fake_marsio_buff_set_rehash_index(marsio_buff_t *m, uint32_t hash) return; } -static int pio_get_marsio_dll_function_entries(void) +static ssize_t pio_get_marsio_dll_function_entries(void) { - void *marsio_so_handle = dlopen(g_engine_instance.config.lib.libmarsio_path, + void *marsio_so_handle = dlopen(g_packet_io_config.marsio.libmarsio_path, RTLD_NOW | RTLD_LOCAL | RTLD_NODELETE); if (nullptr == marsio_so_handle) { printf("\033[1;31;40m[Error]dlopen '%s' failed, %s\033[0m\n", - g_engine_instance.config.lib.libmarsio_path, dlerror()); + g_packet_io_config.marsio.libmarsio_path, dlerror()); return -1; } @@ -43,7 +43,7 @@ static int pio_get_marsio_dll_function_entries(void) (struct mr_instance *(*)(void))dlsym(marsio_so_handle, "marsio_create"); if (nullptr == g_marsio_dll_func.marsio_create) { printf("\033[1;31;40m[Error]dlsym function '%s' from '%s' failed!\033[0m\n", "marsio_create", - g_engine_instance.config.lib.libmarsio_path); + g_packet_io_config.marsio.libmarsio_path); return -1; } @@ -51,7 +51,7 @@ static int pio_get_marsio_dll_function_entries(void) (int (*)(struct mr_instance *, const char *))dlsym(marsio_so_handle, "marsio_init"); if (nullptr == g_marsio_dll_func.marsio_init) { printf("\033[1;31;40m[Error]dlsym function '%s' from '%s' failed!\033[0m\n", "marsio_init", - g_engine_instance.config.lib.libmarsio_path); + g_packet_io_config.marsio.libmarsio_path); return -1; } @@ -59,7 +59,7 @@ static int pio_get_marsio_dll_function_entries(void) (int (*)(struct mr_instance *))dlsym(marsio_so_handle, "marsio_destory"); if (nullptr == g_marsio_dll_func.marsio_destroy) { printf("\033[1;31;40m[Error]dlsym function '%s' from '%s' failed!\033[0m\n", "marsio_destory", - g_engine_instance.config.lib.libmarsio_path); + g_packet_io_config.marsio.libmarsio_path); return -1; } @@ -68,7 +68,7 @@ static int pio_get_marsio_dll_function_entries(void) unsigned int, unsigned int))dlsym(marsio_so_handle, "marsio_open_device"); if (nullptr == g_marsio_dll_func.marsio_open_device) { printf("\033[1;31;40m[Error]dlsym function '%s' from '%s' failed!\033[0m\n", "marsio_open_device", - g_engine_instance.config.lib.libmarsio_path); + g_packet_io_config.marsio.libmarsio_path); return -1; } @@ -76,7 +76,7 @@ static int pio_get_marsio_dll_function_entries(void) (void (*)(struct mr_vdev *))dlsym(marsio_so_handle, "marsio_close_device"); if (nullptr ==g_marsio_dll_func.marsio_close_device) { printf("\033[1;31;40m[Error]dlsym function '%s' from '%s' failed!\033[0m\n", "marsio_close_device", - g_engine_instance.config.lib.libmarsio_path); + g_packet_io_config.marsio.libmarsio_path); return -1; } @@ -84,7 +84,7 @@ static int pio_get_marsio_dll_function_entries(void) (int (*)(struct mr_instance *, marsio_opt_type_t, void *, size_t))dlsym(marsio_so_handle, "marsio_option_set"); if (nullptr == g_marsio_dll_func.marsio_option_set) { printf("\033[1;31;40m[Error]dlsym function '%s' from '%s' failed!\033[0m\n", "marsio_option_set", - g_engine_instance.config.lib.libmarsio_path); + g_packet_io_config.marsio.libmarsio_path); return -1; } @@ -92,7 +92,7 @@ static int pio_get_marsio_dll_function_entries(void) (struct mr_sendpath *(*)(struct mr_vdev *))dlsym(marsio_so_handle, "marsio_sendpath_create_by_vdev"); if (nullptr == g_marsio_dll_func.marsio_sendpath_create_by_vdev) { printf("\033[1;31;40m[Error]dlsym function '%s' from '%s' failed!\033[0m\n", "marsio_sendpath_create_by_vdev", - g_engine_instance.config.lib.libmarsio_path); + g_packet_io_config.marsio.libmarsio_path); return -1; } @@ -100,14 +100,14 @@ static int pio_get_marsio_dll_function_entries(void) (void (*)(struct mr_sendpath *))dlsym(marsio_so_handle, "marsio_sendpath_destory"); if (nullptr == g_marsio_dll_func.marsio_sendpath_destroy) { printf("\033[1;31;40m[Error]dlsym function '%s' from '%s' failed!\033[0m\n", "marsio_sendpath_destory", - g_engine_instance.config.lib.libmarsio_path); + g_packet_io_config.marsio.libmarsio_path); return -1; } g_marsio_dll_func.marsio_thread_init = (int (*)(struct mr_instance *))dlsym(marsio_so_handle, "marsio_thread_init"); if (nullptr == g_marsio_dll_func.marsio_thread_init) { printf("\033[1;31;40m[Error]dlsym function '%s' from '%s' failed!\033[0m\n", "marsio_thread_init", - g_engine_instance.config.lib.libmarsio_path); + g_packet_io_config.marsio.libmarsio_path); return -1; } @@ -115,7 +115,7 @@ static int pio_get_marsio_dll_function_entries(void) (int (*)(struct mr_vdev *, queue_id_t, marsio_buff_t **, int))dlsym(marsio_so_handle, "marsio_recv_burst"); if (nullptr == g_marsio_dll_func.marsio_recv_burst) { printf("\033[1;31;40m[Error]dlsym function '%s' from '%s' failed!\033[0m\n", "marsio_recv_burst", - g_engine_instance.config.lib.libmarsio_path); + g_packet_io_config.marsio.libmarsio_path); return -1; } @@ -123,7 +123,7 @@ static int pio_get_marsio_dll_function_entries(void) (int (*)(struct mr_sendpath *, queue_id_t, marsio_buff_t **, int))dlsym(marsio_so_handle, "marsio_send_burst"); if (nullptr == g_marsio_dll_func.marsio_send_burst) { printf("\033[1;31;40m[Error]dlsym function '%s' from '%s' failed!\033[0m\n", "marsio_send_burst", - g_engine_instance.config.lib.libmarsio_path); + g_packet_io_config.marsio.libmarsio_path); return -1; } @@ -132,7 +132,7 @@ static int pio_get_marsio_dll_function_entries(void) marsio_buff_t **, int, uint16_t))dlsym(marsio_so_handle, "marsio_send_burst_with_options"); if (nullptr == g_marsio_dll_func.marsio_send_burst_with_options) { printf("\033[1;31;40m[Error]dlsym function '%s' from '%s' failed!\033[0m\n", "marsio_send_burst_with_options", - g_engine_instance.config.lib.libmarsio_path); + g_packet_io_config.marsio.libmarsio_path); return -1; } @@ -141,7 +141,7 @@ static int pio_get_marsio_dll_function_entries(void) unsigned int, int, int))dlsym(marsio_so_handle, "marsio_buff_malloc_global"); if (nullptr == g_marsio_dll_func.marsio_buff_malloc_global) { printf("\033[1;31;40m[Error]dlsym function '%s' from '%s' failed!\033[0m\n", "marsio_buff_malloc_global", - g_engine_instance.config.lib.libmarsio_path); + g_packet_io_config.marsio.libmarsio_path); return -1; } @@ -150,7 +150,7 @@ static int pio_get_marsio_dll_function_entries(void) unsigned int, int, int))dlsym(marsio_so_handle, "marsio_buff_free"); if (nullptr == g_marsio_dll_func.marsio_buff_free) { printf("\033[1;31;40m[Error]dlsym function '%s' from '%s' failed!\033[0m\n", "marsio_buff_free", - g_engine_instance.config.lib.libmarsio_path); + g_packet_io_config.marsio.libmarsio_path); return -1; } @@ -158,7 +158,7 @@ static int pio_get_marsio_dll_function_entries(void) (char * (*)(marsio_buff_t *, uint16_t))dlsym(marsio_so_handle, "marsio_buff_append"); if (nullptr == g_marsio_dll_func.marsio_buff_append) { printf("\033[1;31;40m[Error]dlsym function '%s' from '%s' failed!\033[0m\n", "marsio_buff_append", - g_engine_instance.config.lib.libmarsio_path); + g_packet_io_config.marsio.libmarsio_path); return -1; } @@ -166,7 +166,7 @@ static int pio_get_marsio_dll_function_entries(void) (void * (*)(marsio_buff_t *, uint8_t))dlsym(marsio_so_handle, "marsio_buff_ctrlzone"); if (nullptr == g_marsio_dll_func.marsio_buff_ctrlzone) { printf("\033[1;31;40m[Error]dlsym function '%s' from '%s' failed!\033[0m\n", "marsio_buff_ctrlzone", - g_engine_instance.config.lib.libmarsio_path); + g_packet_io_config.marsio.libmarsio_path); return -1; } @@ -175,7 +175,7 @@ static int pio_get_marsio_dll_function_entries(void) void *, uint8_t))dlsym(marsio_so_handle, "marsio_buff_ctrlzone_set"); if (nullptr == g_marsio_dll_func.marsio_buff_ctrlzone_set) { printf("\033[1;31;40m[Error]dlsym function '%s' from '%s' failed!\033[0m\n", "marsio_buff_ctrlzone_set", - g_engine_instance.config.lib.libmarsio_path); + g_packet_io_config.marsio.libmarsio_path); return -1; } @@ -183,28 +183,28 @@ static int pio_get_marsio_dll_function_entries(void) (void (*)(marsio_buff_t *, uint32_t))dlsym(marsio_so_handle, "marsio_buff_set_rehash_index"); if (nullptr == g_marsio_dll_func.marsio_buff_set_rehash_index) { printf("\033[1;31;40m[Error]dlsym function '%s' from '%s' failed!\033[0m\n", "marsio_buff_set_rehash_index", - g_engine_instance.config.lib.libmarsio_path); + g_packet_io_config.marsio.libmarsio_path); g_marsio_dll_func.marsio_buff_set_rehash_index = fake_marsio_buff_set_rehash_index; } g_marsio_dll_func.marsio_buff_mtod = (char * (*)(marsio_buff_t *))dlsym(marsio_so_handle, "marsio_buff_mtod"); if (nullptr == g_marsio_dll_func.marsio_buff_mtod) { printf("\033[1;31;40m[Error]dlsym function '%s' from '%s' failed!\033[0m\n", "marsio_buff_mtod", - g_engine_instance.config.lib.libmarsio_path); + g_packet_io_config.marsio.libmarsio_path); return -1; } g_marsio_dll_func.marsio_buff_datalen = (uint32_t (*)(marsio_buff_t *))dlsym(marsio_so_handle, "marsio_buff_datalen"); if (nullptr == g_marsio_dll_func.marsio_buff_datalen) { printf("\033[1;31;40m[Error]dlsym function '%s' from '%s' failed!\033[0m\n", "marsio_buff_datalen", - g_engine_instance.config.lib.libmarsio_path); + g_packet_io_config.marsio.libmarsio_path); return -1; } g_marsio_dll_func.marsio_buff_buflen = (uint32_t (*)(marsio_buff_t *))dlsym(marsio_so_handle, "marsio_buff_buflen"); if (nullptr == g_marsio_dll_func.marsio_buff_buflen) { printf("\033[1;31;40m[Error]dlsym function '%s' from '%s' failed!\033[0m\n", "marsio_buff_buflen", - g_engine_instance.config.lib.libmarsio_path); + g_packet_io_config.marsio.libmarsio_path); return -1; } @@ -213,7 +213,7 @@ static int pio_get_marsio_dll_function_entries(void) int, int, uint16_t))dlsym(marsio_so_handle, "marsio_buff_clone_with_options"); if (nullptr == g_marsio_dll_func.marsio_buff_clone_with_options) { printf("\033[1;31;40m[Error]dlsym function '%s' from '%s' failed!\033[0m\n", "marsio_buff_clone_with_options", - g_engine_instance.config.lib.libmarsio_path); + g_packet_io_config.marsio.libmarsio_path); return -1; } @@ -222,7 +222,7 @@ static int pio_get_marsio_dll_function_entries(void) (void (*)(struct mr_sendpath *, queue_id_t))dlsym(marsio_so_handle, "marsio_send_burst_flush"); if (nullptr == g_marsio_dll_func.marsio_send_burst_flush) { printf("\033[33m[Warning]dlsym function '%s' from '%s' failed!\033[0m\n", "marsio_send_burst_flush", - g_engine_instance.config.lib.libmarsio_path); + g_packet_io_config.marsio.libmarsio_path); } /* for vlan flipping */ @@ -231,7 +231,7 @@ static int pio_get_marsio_dll_function_entries(void) void *, unsigned int))dlsym(marsio_so_handle, "marsio_buff_get_metadata"); if (nullptr == g_marsio_dll_func.marsio_buff_get_metadata) { printf("\033[33m[Error]dlsym function '%s' from '%s' failed!\033[0m\n", "marsio_buff_get_metadata", - g_engine_instance.config.lib.libmarsio_path); + g_packet_io_config.marsio.libmarsio_path); /* in order to be forward compatible with the previous version of mrzcpd, no error is returned here. vlan_flipping will become invalid @@ -243,7 +243,7 @@ static int pio_get_marsio_dll_function_entries(void) void *, unsigned int))dlsym(marsio_so_handle, "marsio_buff_set_metadata"); if (nullptr == g_marsio_dll_func.marsio_buff_get_metadata) { printf("\033[33m[Error]dlsym function '%s' from '%s' failed!\033[0m\n", "marsio_buff_set_metadata", - g_engine_instance.config.lib.libmarsio_path); + g_packet_io_config.marsio.libmarsio_path); /* in order to be forward compatible with the previous version of mrzcpd, no error is returned here. vlan_flipping will become invalid @@ -254,7 +254,7 @@ static int pio_get_marsio_dll_function_entries(void) (int (*)(marsio_buff_t *, enum mr_buff_metadata_type))dlsym(marsio_so_handle, "marsio_buff_unset_metadata"); if (nullptr == g_marsio_dll_func.marsio_buff_unset_metadata) { printf("\033[33m[Error]dlsym function '%s' from '%s' failed!\033[0m\n", "marsio_buff_unset_metadata", - g_engine_instance.config.lib.libmarsio_path); + g_packet_io_config.marsio.libmarsio_path); /* in order to be forward compatible with the previous version of mrzcpd, no error is returned here. vlan_flipping will become invalid @@ -264,7 +264,7 @@ static int pio_get_marsio_dll_function_entries(void) return 0; } -int pio_marsio_device_open(struct packet_io_device *pdev) +ssize_t pio_marsio_device_open(struct packet_io_device *pdev) { if (nullptr == pdev) { log_error(ST_ERR_PIO_MARSIO_DEVICE, "invalid packet_io_device pointer."); @@ -282,7 +282,7 @@ int pio_marsio_device_open(struct packet_io_device *pdev) return -1; } - pdev->entity.marsio_dev_ctx->pio_dev = pdev; + pdev->entity.marsio_dev_ctx->pdev = pdev; struct mr_instance *mr_inst_handle = pdev->ppio_inst->entity.marsio_inst_ctx->mr_inst_handle; /* marsio_open_device() return marsio device handle*/ @@ -304,7 +304,7 @@ int pio_marsio_device_open(struct packet_io_device *pdev) return 0; } -int pio_marsio_device_close(struct packet_io_device *pdev) +ssize_t pio_marsio_device_close(struct packet_io_device *pdev) { if (nullptr == pdev) { log_error(ST_ERR_PIO_MARSIO_DEVICE, "invalid pdev pointer so close marsio device failed!"); @@ -319,12 +319,12 @@ int pio_marsio_device_close(struct packet_io_device *pdev) return 0; } -int pio_marsio_device_receive(struct packet_io_device *pdev, uint16_t rxq_id, struct stellar_packet **pkts, int nr_pkts) +ssize_t pio_marsio_device_receive(struct packet_io_device *pdev, uint32_t rxq_id, struct stellar_packet **pkts, size_t nr_pkts) { struct mr_vdev *mr_dev_handle = pdev->entity.marsio_dev_ctx->mr_dev_handle; marsio_buff_t *rx_buff[MARSIO_BURST_PKT_MAX]; - int recv_res = g_marsio_dll_func.marsio_recv_burst(mr_dev_handle, rxq_id, rx_buff, nr_pkts); + ssize_t recv_res = g_marsio_dll_func.marsio_recv_burst(mr_dev_handle, rxq_id, rx_buff, nr_pkts); /* receive some pkts, copy mbuf pointer to packet structure */ if (recv_res > 0) { for (int i = 0; i < recv_res; i++) { @@ -335,10 +335,10 @@ int pio_marsio_device_receive(struct packet_io_device *pdev, uint16_t rxq_id, st return recv_res; } -int pio_marsio_device_send(struct packet_io_device *pdev, uint16_t txq_id, struct stellar_packet **pkts, int nr_pkts) +ssize_t pio_marsio_device_send(struct packet_io_device *pdev, uint32_t txq_id, struct stellar_packet **pkts, size_t nr_pkts) { struct mr_sendpath *sendpath_handle = pdev->entity.marsio_dev_ctx->mr_sendpath_handle; - int ret = g_marsio_dll_func.marsio_send_burst(sendpath_handle, txq_id, (marsio_buff_t **)pkts, nr_pkts); + ssize_t ret = g_marsio_dll_func.marsio_send_burst(sendpath_handle, txq_id, (marsio_buff_t **)pkts, nr_pkts); if (ret < 0) { g_marsio_dll_func.marsio_buff_free(pdev->ppio_inst->entity.marsio_inst_ctx->mr_inst_handle, (marsio_buff_t **)pkts, nr_pkts, MARSIO_SOCKET_ID_ANY, txq_id); @@ -347,15 +347,15 @@ int pio_marsio_device_send(struct packet_io_device *pdev, uint16_t txq_id, struc return ret; } -void pio_marsio_device_pkt_free(struct packet_io_device *pdev, uint16_t qid, struct stellar_packet **pkts, int nr_pkts) +void pio_marsio_device_pkt_free(struct packet_io_device *pdev, uint32_t qid, struct stellar_packet **pkts, size_t nr_pkts) { struct mr_instance *mr_inst = pdev->ppio_inst->entity.marsio_inst_ctx->mr_inst_handle; g_marsio_dll_func.marsio_buff_free(mr_inst, (marsio_buff_t **)pkts, nr_pkts, MARSIO_SOCKET_ID_ANY, qid); } -static int marsio_instance_init(struct packet_io_instance *pinst) +static ssize_t marsio_instance_init(struct packet_io_instance *pinst) { - int ret = -1; + ssize_t ret = -1; ret = pio_get_marsio_dll_function_entries(); if (ret < 0) { printf("\033[1;31;40m[Error]dlopen marsio.so symbol failed!\033[0m\n"); @@ -368,7 +368,7 @@ static int marsio_instance_init(struct packet_io_instance *pinst) return -1; } - int wrk_thread_num = g_engine_instance.config.packet_io.thread_num; + int wrk_thread_num = g_packet_io_config.common.thread_num; /* TODO: MARSIO_OPT_THREAD_NUM */ ret = g_marsio_dll_func.marsio_option_set(pinst->entity.marsio_inst_ctx->mr_inst_handle, MARSIO_OPT_THREAD_NUM, @@ -390,7 +390,7 @@ static int marsio_instance_init(struct packet_io_instance *pinst) return 0; } -int pio_marsio_instance_create(struct packet_io_instance *pinst) +ssize_t pio_marsio_instance_create(struct packet_io_instance *pinst) { if (nullptr == pinst) { log_error(ST_ERR_PIO_MARSIO_INSTANCE, "invalid marsio instance pointer."); @@ -404,7 +404,7 @@ int pio_marsio_instance_create(struct packet_io_instance *pinst) } /* instance init */ - int ret = marsio_instance_init(pinst); + ssize_t ret = marsio_instance_init(pinst); if (ret < 0) { log_error(ST_ERR_PIO_MARSIO_INSTANCE, "marsio instance init failed."); return -1; @@ -418,30 +418,24 @@ void pio_marsio_instance_destroy(struct packet_io_instance *pinst) g_marsio_dll_func.marsio_destroy(pinst->entity.marsio_inst_ctx->mr_inst_handle); FREE(pinst->entity.marsio_inst_ctx); - for (uint32_t i = 0; i < pinst->dev_cnt; i++) { - pio_marsio_device_close(pinst->devices[i]); - FREE(pinst->devices[i]); + struct packet_io_device *node = nullptr; + while ((node = TAILQ_FIRST(&pinst->device_queue_head)) != nullptr) { + TAILQ_REMOVE(&pinst->device_queue_head, node, next); + pinst->dev_cnt--; + pio_marsio_device_close(node); + FREE(node); } } -void *pio_marsio_device_buff_ctrlzone(struct stellar_packet *p) +char *pio_marsio_device_buff_ctrlzone(struct stellar_packet *p, size_t *ctrlzone_len) { int zone_id = 0; - - return g_marsio_dll_func.marsio_buff_ctrlzone((marsio_buff_t *)p, zone_id); + *ctrlzone_len = (size_t)g_marsio_dll_func.marsio_buff_buflen((marsio_buff_t *)p); + return (char *)g_marsio_dll_func.marsio_buff_ctrlzone((marsio_buff_t *)p, zone_id); } -char *pio_marsio_device_buff_mtod(struct stellar_packet *p) +char *pio_marsio_device_buff_mtod(struct stellar_packet *p, size_t *data_len) { + *data_len = (size_t)g_marsio_dll_func.marsio_buff_datalen((marsio_buff_t *)p); return g_marsio_dll_func.marsio_buff_mtod((marsio_buff_t *)p); -} - -uint32_t pio_marsio_device_buff_buflen(struct stellar_packet *p) -{ - return g_marsio_dll_func.marsio_buff_buflen((marsio_buff_t *)p); -} - -uint32_t pio_marsio_device_buff_datalen(struct stellar_packet *p) -{ - return g_marsio_dll_func.marsio_buff_datalen((marsio_buff_t *)p); -} +} \ No newline at end of file diff --git a/src/packet_io/marsio_mode/pio_marsio.h b/src/packet_io/marsio_mode/pio_marsio.h index 0e4814a..cf640d6 100644 --- a/src/packet_io/marsio_mode/pio_marsio.h +++ b/src/packet_io/marsio_mode/pio_marsio.h @@ -98,7 +98,7 @@ struct pio_marsio_device_context { struct mr_vdev *mr_dev_handle; struct mr_sendpath * mr_sendpath_handle; - struct packet_io_device *pio_dev; + struct packet_io_device *pdev; }; /** @@ -107,7 +107,7 @@ struct pio_marsio_device_context { * @param pinst * @return int */ -int pio_marsio_instance_create(struct packet_io_instance *pinst); +ssize_t pio_marsio_instance_create(struct packet_io_instance *pinst); /** * @brief @@ -124,12 +124,12 @@ void pio_marsio_instance_destroy(struct packet_io_instance *pinst); * pdev->rxq_num: number of the packet receiving queues for the device * pdev->txq_num: number of the packet sending queues for the device */ -int pio_marsio_device_open(struct packet_io_device *pdev); +ssize_t pio_marsio_device_open(struct packet_io_device *pdev); /** * @brief close pcap_live device */ -int pio_marsio_device_close(struct packet_io_device *pdev); +ssize_t pio_marsio_device_close(struct packet_io_device *pdev); /** * @brief receive packets from device's single rx queue which specified by rxq_id @@ -141,7 +141,7 @@ int pio_marsio_device_close(struct packet_io_device *pdev); * * @retval number of packets actually received */ -int pio_marsio_device_receive(struct packet_io_device *pdev, uint16_t rxq_id, struct stellar_packet **pkts, int nr_pkts); +ssize_t pio_marsio_device_receive(struct packet_io_device *pdev, uint32_t rxq_id, struct stellar_packet **pkts, size_t nr_pkts); /** * @brief send packets by device's single tx queue which specified by txq_id @@ -153,7 +153,7 @@ int pio_marsio_device_receive(struct packet_io_device *pdev, uint16_t rxq_id, st * * @retval if ret<0, means the sending fails; if ret==0 means the sending succeeds */ -int pio_marsio_device_send(struct packet_io_device *pdev, uint16_t txq_id, struct stellar_packet **pkts, int nr_pkts); +ssize_t pio_marsio_device_send(struct packet_io_device *pdev, uint32_t txq_id, struct stellar_packet **pkts, size_t nr_pkts); /** * @brief manually free packet's memory @@ -163,15 +163,11 @@ int pio_marsio_device_send(struct packet_io_device *pdev, uint16_t txq_id, struc * @param pkts: * @param nr_pkts: */ -void pio_marsio_device_pkt_free(struct packet_io_device *pdev, uint16_t qid, struct stellar_packet **pkts, int nr_pkts); +void pio_marsio_device_pkt_free(struct packet_io_device *pdev, uint32_t qid, struct stellar_packet **pkts, size_t nr_pkts); -void *pio_marsio_device_buff_ctrlzone(struct stellar_packet *p); +char *pio_marsio_device_buff_ctrlzone(struct stellar_packet *p, size_t *ctrlzone_len); -char *pio_marsio_device_buff_mtod(struct stellar_packet *p); - -uint32_t pio_marsio_device_buff_buflen(struct stellar_packet *p); - -uint32_t pio_marsio_device_buff_datalen(struct stellar_packet *p); +char *pio_marsio_device_buff_mtod(struct stellar_packet *p, size_t *data_len); #ifdef __cpluscplus } diff --git a/src/packet_io/packet_io.cpp b/src/packet_io/packet_io.cpp deleted file mode 100644 index 957034b..0000000 --- a/src/packet_io/packet_io.cpp +++ /dev/null @@ -1,203 +0,0 @@ -/* -********************************************************************************************** -* File: packet_io.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" - -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 = nullptr, - .pkt_free = pio_pcap_file_device_pkt_free, - .buff_ctrlzone = pio_pcap_file_device_buff_ctrlzone, - .buff_mtod = pio_pcap_file_device_buff_mtod, - .buff_buflen = pio_pcap_file_device_buff_buflen, - .buff_datalen = pio_pcap_file_device_buff_datalen, - }, - - { - .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, - .buff_buflen = pio_pcap_live_device_buff_buflen, - .buff_datalen = pio_pcap_live_device_buff_datalen, - }, - - { - .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, - .buff_buflen = pio_marsio_device_buff_buflen, - .buff_datalen = pio_marsio_device_buff_datalen, - } -}; - -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; - } - - int 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; - } - - 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; -} - -void packet_io_instance_destroy(struct packet_io_instance *pinst) { - if (nullptr == pinst) { - return; - } - - pinst->inst_ops->destroy(pinst); - FREE(pinst); -} - -struct packet_io_device * -packet_io_device_open(struct packet_io_instance *pinst, const char *dev_name, uint16_t nr_rxq, uint16_t nr_txq) -{ - struct packet_io_device *ppio_dev = CALLOC(struct packet_io_device, 1); - if (nullptr == ppio_dev) { - log_error(ST_ERR_MEM_ALLOC, "packet_io device alloc failed."); - return nullptr; - } - - int ret = strncpy_safe(ppio_dev->dev_name, dev_name, sizeof(ppio_dev->dev_name)); - if (ret < 0) { - log_error(ST_ERR_STR_COPY, "packet_io device name copy failed."); - return nullptr; - } - - ppio_dev->rxq_num = nr_rxq; - ppio_dev->txq_num = nr_txq; - ppio_dev->ppio_inst = pinst; - ppio_dev->dev_ops = &pio_device_ops_array[pinst->mode]; - - /* - * ppio_inst->devices --> | struct packet_io_device * | struct packet_io_device * | struct packet_io_device * | - array[0] array[1] array[2] - **/ - pinst->devices[pinst->dev_cnt++] = ppio_dev; - - ret = ppio_dev->dev_ops->open(ppio_dev); - if (ret < 0) { - log_error(ST_ERR_PIO_DEVICE, "packet_io device open failed."); - FREE(ppio_dev); - return nullptr; - } - - return ppio_dev; -} - -void packet_io_device_close(struct packet_io_device *pdev) -{ - if (nullptr == pdev) { - return; - } - - if (nullptr == pdev->dev_ops) { - FREE(pdev); - return; - } - - int ret = pdev->dev_ops->close(pdev); - if (ret < 0) { - log_error(ST_ERR_PIO_DEVICE, "packet_io device close failed."); - } - - FREE(pdev); -} - -int packet_io_device_rx(struct packet_io_device *pdev, uint16_t rxq_id, struct stellar_packet **pkts, int nr_pkts) -{ - return pdev->dev_ops->recv(pdev, rxq_id, pkts, nr_pkts); -} - -int packet_io_device_tx(struct packet_io_device *pdev, uint16_t txq_id, struct stellar_packet **pkts, int nr_pkts) -{ - return pdev->dev_ops->send(pdev, txq_id, pkts, nr_pkts); -} - -void packet_io_pkts_free(struct packet_io_device *pdev, uint16_t qid, struct stellar_packet **pkts, int nr_pkts) -{ - return pdev->dev_ops->pkt_free(pdev, qid, pkts, nr_pkts); -} - -void *packet_io_buff_ctrlzone(struct packet_io_device *pdev, struct stellar_packet *p) -{ - return pdev->dev_ops->buff_ctrlzone(p); -} - -char *packet_io_buff_mtod(struct packet_io_device *pdev, struct stellar_packet *p) -{ - return pdev->dev_ops->buff_mtod(p); -} - -uint32_t packet_io_buff_buflen(struct packet_io_device *pdev, struct stellar_packet *p) -{ - return pdev->dev_ops->buff_buflen(p); -} - -uint32_t packet_io_buff_datalen(struct packet_io_device *pdev, struct stellar_packet *p) -{ - return pdev->dev_ops->buff_datalen(p); -} diff --git a/src/packet_io/packet_io.h b/src/packet_io/packet_io.h index fc55082..868bb15 100644 --- a/src/packet_io/packet_io.h +++ b/src/packet_io/packet_io.h @@ -17,119 +17,50 @@ extern "C" #endif #include -#include -#include +#include +#include -#include "global_var.h" -#include "./pcap_live_mode/pio_pcap_live.h" -#include "./pcap_file_mode/pio_pcap_file.h" -#include "./marsio_mode/pio_marsio.h" +enum packet_io_run_mode { + PACKET_IO_RUN_MODE_PCAP_FILE, + PACKET_IO_RUN_MODE_PCAP_LIVE, + PACKET_IO_RUN_MODE_MARSIO, + PACKET_IO_RUN_MODE_MAX, +}; + +struct packet_io_instance; +struct packet_io_device; /** - * note: - * 1. packet_io_XXX function is supported by packet_io.h - * 2. pio_XXX function is supported by pio_pcap_live.h/pio_pcap_file.h/pio_marsio.h - */ - -struct pio_instance_operations { - int (*create)(struct packet_io_instance *pinst); - - void (*destroy)(struct packet_io_instance *pinst); -}; - -struct packet_io_instance { - /* packet_io instance name */ - char inst_name[NAME_MAX]; - - /* packet_io run mode of the instance */ - enum packet_io_run_mode mode; - - /* device handle set in this instance */ - struct packet_io_device *devices[DEV_MAX_CNT]; - - /* device's exactly count */ - uint32_t dev_cnt; - - /* instance operations */ - struct pio_instance_operations *inst_ops; - - union - { - struct pio_pcap_file_instance_context *pcap_file_inst_ctx; - struct pio_pcap_live_instance_context *pcap_live_inst_ctx; - struct pio_marsio_instance_context *marsio_inst_ctx; - } entity; -}; - -struct pio_device_operations { - int (*open)(struct packet_io_device *pdev); - - int (*close)(struct packet_io_device *pdev); - - int (*recv)(struct packet_io_device *pdev, uint16_t rxq_id, struct stellar_packet **pkts, int nr_pkts); - - int (*send)(struct packet_io_device *pdev, uint16_t txq_id, struct stellar_packet **pkts, int nr_pkts); - - void (*pkt_free)(struct packet_io_device *pdev, uint16_t qid, struct stellar_packet **pkts, int nr_pkts); - - void *(*buff_ctrlzone)(struct stellar_packet *p); - - char *(*buff_mtod)(struct stellar_packet *p); - - uint32_t (*buff_buflen)(struct stellar_packet *p); - - uint32_t (*buff_datalen)(struct stellar_packet *p); -}; - -struct packet_io_device { - /* device name */ - char dev_name[NAME_MAX]; - - /* device operations */ - struct pio_device_operations *dev_ops; - - /* number of receive queue */ - uint16_t rxq_num; - - /* number of send queue */ - uint16_t txq_num; - - /* packet io device context */ - union { - struct pio_pcap_file_device_context *pcap_file_dev_ctx; - struct pio_pcap_live_device_context *pcap_live_dev_ctx; - struct pio_marsio_device_context *marsio_dev_ctx; - } entity; - - /* packet_io instance which the device belongs to */ - struct packet_io_instance *ppio_inst; -}; - -/** - * @brief create packet_io instance which will manage packet_io device - * - * @param instance_name: packet_io instance name - * @param mode: packet_io run mode + * @brief + * + * @param instance_name: packet_io instance's name + * @param filename: packet_io config file's name + * @param devices(in/out): return packet_io_device pointer array, each pointer stands for an opened packet_io device + * @param dev_num: the num of opened packet_io_device's pointer + * @return struct packet_io_instance* */ struct packet_io_instance * -packet_io_instance_create(const char *instance_name, const enum packet_io_run_mode mode); +packet_io_init(const char *instance_name, const char *filename, struct packet_io_device *devices[], size_t *dev_num); /* destroy packet_io instance */ -void packet_io_instance_destroy(struct packet_io_instance *pinst); +void packet_io_fini(struct packet_io_instance *pinst); /** - * @brief open packet_io device for send/receive packets - * - * @param pinst: packet_io instance pointer - * @param dev_name: packet_io device name - * @param nr_rxq: number of receive queue for the device - * @param nr_txq: number of send queue for the device + * @brief + * + * @param inst_name + * @param mode + * @return struct packet_io_instance* */ -struct packet_io_device * -packet_io_device_open(struct packet_io_instance *pinst, const char *dev_name, uint16_t nr_rxq, uint16_t nr_txq); +struct packet_io_instance * +packet_io_instance_create(const char *inst_name, const enum packet_io_run_mode mode); -/** close packet_io device */ -void packet_io_device_close(struct packet_io_device *dev); +void packet_io_instance_destroy(struct packet_io_instance *pinst); + +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); + +void packet_io_device_close(struct packet_io_device *pdev); /** * @brief packet_io device receive function @@ -139,7 +70,7 @@ void packet_io_device_close(struct packet_io_device *dev); * @param p: received packet's pointer array * @param nr_p: number of received packets */ -int packet_io_device_rx(struct packet_io_device *pdev, uint16_t rxq_id, struct stellar_packet **pkts, int nr_pkts); +ssize_t packet_io_device_rx(struct packet_io_device *pdev, uint32_t rxq_id, struct stellar_packet **pkts, size_t nr_pkts); /** * @brief packet_io device send function @@ -149,33 +80,12 @@ int packet_io_device_rx(struct packet_io_device *pdev, uint16_t rxq_id, struct s * @param p: prepare to send packet's pointer array * @param nr_p: number of packets which prepare to send */ -int packet_io_device_tx(struct packet_io_device *pdev, uint16_t txq_id, struct stellar_packet **pkts, int 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); /* * @brief packet_io free packet buff */ -void packet_io_pkts_free(struct packet_io_device *pdev, uint16_t qid, struct stellar_packet **pkts, int nr_pkts); - -/** - * @brief get packet_io packet's ctrlzone - * @note ctrlzone's memory is 64 bytes, do not exceed it - */ -void *packet_io_buff_ctrlzone(struct packet_io_device *pdev, struct stellar_packet *p); - -/** - * @brief get packet_io packet's data pointer - */ -char *packet_io_buff_mtod(struct packet_io_device *pdev, struct stellar_packet *p); - -/** - * @brief get packet_io packet's buffer length - */ -uint32_t packet_io_buff_buflen(struct packet_io_device *pdev, struct stellar_packet *p); - -/** - * @brief get packet_io packet's data length - */ -uint32_t packet_io_buff_datalen(struct packet_io_device *pdev, struct stellar_packet *p); +void packet_io_pkts_free(struct packet_io_device *pdev, uint32_t qid, struct stellar_packet **pkts, size_t nr_pkts); #ifdef __cpluscplus } diff --git a/src/packet_io/packet_io_internal.cpp b/src/packet_io/packet_io_internal.cpp new file mode 100644 index 0000000..0a9e78e --- /dev/null +++ b/src/packet_io/packet_io_internal.cpp @@ -0,0 +1,461 @@ +/* +********************************************************************************************** +* 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 = nullptr, + .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)); + 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); +} \ No newline at end of file diff --git a/src/packet_io/packet_io_internal.h b/src/packet_io/packet_io_internal.h new file mode 100644 index 0000000..e52dd7c --- /dev/null +++ b/src/packet_io/packet_io_internal.h @@ -0,0 +1,155 @@ +/* +********************************************************************************************** +* File: packet_io_internal.h +* Description: packet_io internal api +* Authors: Liu WenTan +* Date: 2022-07-15 +* Copyright: (c) 2018-2022 Geedge Networks, Inc. All rights reserved. +*********************************************************************************************** +*/ + +#ifndef _PACKET_IO_INTERNAL_H_ +#define _PACKET_IO_INTERNAL_H_ + +#ifdef __cpluscplus +extern "C" +{ +#endif + +#include +#include + +#include "packet_io_util.h" + +#define DEV_MAX_CNT 64 + +/** + * note: + * 1. packet_io_XXX function is supported by packet_io.h + * 2. pio_XXX function is supported by pio_pcap_live.h/pio_pcap_file.h/pio_marsio.h + */ + +struct pio_instance_operations { + ssize_t (*create)(struct packet_io_instance *pinst); + + void (*destroy)(struct packet_io_instance *pinst); +}; + +struct packet_io_instance { + /* packet_io instance name */ + char inst_name[NAME_MAX]; + + /* packet_io run mode of the instance */ + enum packet_io_run_mode mode; + + /* device handle set in this instance */ + TAILQ_HEAD(pio_device_queue, packet_io_device) device_queue_head; + + /* device's exactly count */ + uint32_t dev_cnt; + + /* instance operations */ + struct pio_instance_operations *inst_ops; + + union + { + struct pio_pcap_file_instance_context *pcap_file_inst_ctx; + struct pio_pcap_live_instance_context *pcap_live_inst_ctx; + struct pio_marsio_instance_context *marsio_inst_ctx; + } entity; +}; + +struct pio_device_operations { + ssize_t (*open)(struct packet_io_device *pdev); + + ssize_t (*close)(struct packet_io_device *pdev); + + ssize_t (*recv)(struct packet_io_device *pdev, uint32_t rxq_id, struct stellar_packet **pkts, size_t nr_pkts); + + ssize_t (*send)(struct packet_io_device *pdev, uint32_t txq_id, struct stellar_packet **pkts, size_t nr_pkts); + + void (*pkt_free)(struct packet_io_device *pdev, uint32_t qid, struct stellar_packet **pkts, size_t nr_pkts); + + char *(*buff_ctrlzone)(struct stellar_packet *p, size_t *ctrlzone_len); + + char *(*buff_mtod)(struct stellar_packet *p, size_t *data_len); +}; + +struct packet_io_device { + /* device name */ + char dev_name[NAME_MAX]; + + /* device operations */ + struct pio_device_operations *dev_ops; + + /* number of receive queue */ + uint16_t rxq_num; + + /* number of send queue */ + uint16_t txq_num; + + /* packet io device context */ + union { + struct pio_pcap_file_device_context *pcap_file_dev_ctx; + struct pio_pcap_live_device_context *pcap_live_dev_ctx; + struct pio_marsio_device_context *marsio_dev_ctx; + } entity; + + /* packet_io instance which the device belongs to */ + struct packet_io_instance *ppio_inst; + + TAILQ_ENTRY(packet_io_device) next; +}; + +struct pio_marsio_config { + /* marsio ctrlzone id */ + int mr_ctrlzone_id; + + const char *libmarsio_path; +}; + +struct pio_pcap_config { + char path[PATH_MAX]; + /* bpf filter string, such as "tcp and port 25"*/ + char bpf_string[STR_MAX_LEN]; + + /* delete after the pcap file is processed */ + int should_delete; + + //time_t delay; + + /* snapshot length */ + int snaplen; + + /* promiscuous value */ + int promisc; +}; + +struct pio_common_config { + /* packet_io run mode */ + enum packet_io_run_mode mode; + + /* worker thread num */ + int thread_num; + + /* device name list */ + char dev_name[DEV_MAX_CNT][NAME_MAX]; + + /* device counts */ + uint32_t dev_cnt; +}; + +/* store packet_io configuration */ +struct packet_io_config { + struct pio_common_config common; + struct pio_pcap_config pcap; + struct pio_marsio_config marsio; +}; + +extern struct packet_io_config g_packet_io_config; + +#ifdef __cpluscplus +} +#endif + +#endif /* _PACKET_IO_INTERNAL_H_ */ \ No newline at end of file diff --git a/src/packet_io/packet_io_util.cpp b/src/packet_io/packet_io_util.cpp index c5cc4ac..e94237f 100644 --- a/src/packet_io/packet_io_util.cpp +++ b/src/packet_io/packet_io_util.cpp @@ -16,14 +16,14 @@ #include "utils.h" #include "packet_io_util.h" -static int packet_copy_data_offset(uint8_t *ptr, uint32_t offset, const uint8_t *data, uint32_t data_len) +static ssize_t packet_copy_data_offset(uint8_t *ptr, uint32_t offset, const uint8_t *data, uint32_t data_len) { memcpy(ptr + offset, data, data_len); return 0; } -int packet_copy_data(uint8_t *ptr, const uint8_t *pkt_data, uint32_t pkt_len) +ssize_t packet_copy_data(uint8_t *ptr, const uint8_t *pkt_data, uint32_t pkt_len) { return packet_copy_data_offset(ptr, 0, pkt_data, pkt_len); } @@ -99,12 +99,11 @@ void release_pio_packet_queue(struct pio_packet_queue *q) while (q->len != 0) { struct pio_packet *p = pio_packet_dequeue(q); - q->len--; FREE(p); } } -int strncpy_safe(char *dst, const char *src, size_t dst_size) +ssize_t strncpy_safe(char *dst, const char *src, size_t dst_size) { if (nullptr == dst || nullptr == src || dst_size == 0) { return -1; @@ -173,7 +172,7 @@ static uint64_t generic_2tuple_hash(uint8_t *src, uint8_t *dst, size_t n) uint64_t key1 = simple_murmur_hash(src, n); uint64_t key2 = simple_murmur_hash(dst, n); - return (key1 | key2); + return (key1 ^ key2); } uint64_t pio_packet_hash(struct pio_packet *p) diff --git a/src/packet_io/packet_io_util.h b/src/packet_io/packet_io_util.h index ddd2422..15cc1df 100644 --- a/src/packet_io/packet_io_util.h +++ b/src/packet_io/packet_io_util.h @@ -19,6 +19,8 @@ extern "C" #include #include +#define STR_MAX_LEN 1024 + #ifndef DLT_EN10MB #define DLT_EN10MB 1 #endif @@ -82,9 +84,9 @@ struct pio_packet_queue { * * @retval -1(failed), 0(success) */ -int strncpy_safe(char *dst, const char *src, size_t dst_size); +ssize_t strncpy_safe(char *dst, const char *src, size_t dst_size); -int packet_copy_data(uint8_t *ptr, const uint8_t *pkt_data, uint32_t pkt_len); +ssize_t packet_copy_data(uint8_t *ptr, const uint8_t *pkt_data, uint32_t pkt_len); /** * @brief ip hash function for struct pio_packet, 2 tuple(sip/dip) hash diff --git a/src/packet_io/pcap_file_mode/pio_pcap_file.cpp b/src/packet_io/pcap_file_mode/pio_pcap_file.cpp index 024634b..17c3dce 100644 --- a/src/packet_io/pcap_file_mode/pio_pcap_file.cpp +++ b/src/packet_io/pcap_file_mode/pio_pcap_file.cpp @@ -22,6 +22,7 @@ #include "pio_pcap_file.h" #include "packet_io.h" #include "packet_io_util.h" +#include "packet_io_internal.h" /** * @brief validate path is a valid plain file or directory @@ -30,10 +31,10 @@ * if success, dir == nullptr <---> means path is plain file * dir != nullptr <---> means path is directory */ -static int validate_directory_or_file(const char *path, DIR **dir) +static ssize_t validate_directory_or_file(const char *path, DIR **dir) { DIR *temp_dir = nullptr; - int ret = -1; + ssize_t ret = -1; temp_dir = opendir(path); if (nullptr == temp_dir) { @@ -79,7 +80,7 @@ static bool peek_first_packet_timestamp(struct pcap_plain_file_info *pfile_info) return true; } -static int init_pcap_file(struct pcap_plain_file_info *pfile_info) +static ssize_t init_pcap_file(struct pcap_plain_file_info *pfile_info) { char errbuf[PCAP_ERRBUF_SIZE] = ""; @@ -121,7 +122,7 @@ static int init_pcap_file(struct pcap_plain_file_info *pfile_info) return 0; } -static int pcap_plain_file_init(struct pio_pcap_file_device_context *pfile_dev_ctx, const char *file_name) +static ssize_t pcap_plain_file_init(struct pio_pcap_file_device_context *pfile_dev_ctx, const char *file_name) { if (nullptr == pfile_dev_ctx) { return -1; @@ -154,7 +155,7 @@ static int pcap_plain_file_init(struct pio_pcap_file_device_context *pfile_dev_c return 0; } -static int pcap_directory_file_init(struct pio_pcap_file_device_context *pfile_dev_ctx, const char *dir_name, DIR *directory) +static ssize_t pcap_directory_file_init(struct pio_pcap_file_device_context *pfile_dev_ctx, const char *dir_name, DIR *directory) { if (nullptr == pfile_dev_ctx) { return -1; @@ -173,7 +174,8 @@ static int pcap_directory_file_init(struct pio_pcap_file_device_context *pfile_d return -1; } - //pdir_info->delay = 30; + /* TODO: if should configurable */ + pdir_info->delay = 30; pdir_info->shared = &pfile_dev_ctx->shared; pdir_info->directory = directory; TAILQ_INIT(&pdir_info->file_queue_head); @@ -184,17 +186,17 @@ static int pcap_directory_file_init(struct pio_pcap_file_device_context *pfile_d return 0; } -static int pcap_file_shared_init(struct pio_pcap_file_device_context *pfile_dev_ctx) +static ssize_t pcap_file_shared_init(struct pio_pcap_file_device_context *pfile_dev_ctx) { if (nullptr == pfile_dev_ctx) { return -1; } /* TODO: get conf and assign pfile_dev_ctx->shared */ - if ((g_engine_instance.config.packet_io.mode == PACKET_IO_RUN_MODE_PCAP_FILE) && - g_engine_instance.config.packet_io.bpf_string != nullptr) { + if ((g_packet_io_config.common.mode == PACKET_IO_RUN_MODE_PCAP_FILE) && + g_packet_io_config.pcap.bpf_string != nullptr) { memset(pfile_dev_ctx->shared.bpf_string, 0, sizeof(pfile_dev_ctx->shared.bpf_string)); - int ret = strncpy_safe(pfile_dev_ctx->shared.bpf_string, g_engine_instance.config.packet_io.bpf_string, + ssize_t ret = strncpy_safe(pfile_dev_ctx->shared.bpf_string, g_packet_io_config.pcap.bpf_string, sizeof(pfile_dev_ctx->shared.bpf_string)); if (ret < 0) { log_error(ST_ERR_STR_COPY, "pcap file bpf string copy failed."); @@ -202,7 +204,7 @@ static int pcap_file_shared_init(struct pio_pcap_file_device_context *pfile_dev_ } } - pfile_dev_ctx->shared.should_delete = g_engine_instance.config.packet_io.should_delete; + pfile_dev_ctx->shared.should_delete = g_packet_io_config.pcap.should_delete; /* init pcap file device packet queue */ @@ -239,9 +241,9 @@ static void cleanup_pcap_directory_info(struct pcap_file_directory_info *pdir_in } -int pio_pcap_file_device_open(struct packet_io_device *pdev) +ssize_t pio_pcap_file_device_open(struct packet_io_device *pdev) { - int status = -1; + ssize_t status = -1; DIR *directory = nullptr; if (nullptr == pdev) { @@ -255,7 +257,7 @@ int pio_pcap_file_device_open(struct packet_io_device *pdev) return -1; } - pdev->entity.pcap_file_dev_ctx->pio_dev = pdev; + pdev->entity.pcap_file_dev_ctx->pdev = pdev; status = pcap_file_shared_init(pdev->entity.pcap_file_dev_ctx); if (status < 0) { @@ -287,24 +289,26 @@ int pio_pcap_file_device_open(struct packet_io_device *pdev) return 0; } -int pio_pcap_file_device_close(struct packet_io_device *pdev) +ssize_t pio_pcap_file_device_close(struct packet_io_device *pdev) { if (nullptr == pdev) { log_error(ST_ERR_PIO_PCAP_FILE_DEVICE, "invalid pdev pointer so close pcap file device failed!"); return -1; } - if (pdev->entity.pcap_file_dev_ctx->entity.file != nullptr) { - cleanup_pcap_plain_file_info(pdev->entity.pcap_file_dev_ctx->entity.file); - } + if (pdev->entity.pcap_file_dev_ctx != nullptr) { + if (pdev->entity.pcap_file_dev_ctx->entity.file != nullptr) { + cleanup_pcap_plain_file_info(pdev->entity.pcap_file_dev_ctx->entity.file); + } - if (pdev->entity.pcap_file_dev_ctx->entity.dir != nullptr) { - cleanup_pcap_directory_info(pdev->entity.pcap_file_dev_ctx->entity.dir); - } + if (pdev->entity.pcap_file_dev_ctx->entity.dir != nullptr) { + cleanup_pcap_directory_info(pdev->entity.pcap_file_dev_ctx->entity.dir); + } - for (uint32_t i = 0; i < PKT_QUEUE_MAX_NUM; i++) { - if (pdev->entity.pcap_file_dev_ctx->pkt_queues[i].len != 0) { - release_pio_packet_queue(&pdev->entity.pcap_file_dev_ctx->pkt_queues[i]); + for (uint32_t i = 0; i < PKT_QUEUE_MAX_NUM; i++) { + if (pdev->entity.pcap_file_dev_ctx->pkt_queues[i].len != 0) { + release_pio_packet_queue(&pdev->entity.pcap_file_dev_ctx->pkt_queues[i]); + } } } @@ -341,7 +345,7 @@ void pcap_file_pkt_callback_oneshot(char *user, struct pcap_pkthdr *pkt_hdr, u_c } /* nr_rxq <= PKT_QUEUE_MAX_NUM */ - uint16_t nr_rxq = pfile_dev_ctx->pio_dev->rxq_num; + uint16_t nr_rxq = pfile_dev_ctx->pdev->rxq_num; uint16_t rxq_id = pio_packet_hash(p) % nr_rxq; /* hash to specific queue id and enqueue */ @@ -350,8 +354,8 @@ void pcap_file_pkt_callback_oneshot(char *user, struct pcap_pkthdr *pkt_hdr, u_c pthread_mutex_unlock(&pfile_dev_ctx->pkt_queues[rxq_id].mutex_q); } -static int pcap_file_dispatch(struct pio_pcap_file_device_context *pfile_dev_ctx, uint16_t rxq_id, - struct stellar_packet **pkts, int nr_pkts) +static ssize_t pcap_file_dispatch(struct pio_pcap_file_device_context *pfile_dev_ctx, uint32_t rxq_id, + struct stellar_packet **pkts, size_t nr_pkts) { if (pfile_dev_ctx->entity.file->first_pkt_hdr != nullptr) { pthread_mutex_lock(&pfile_dev_ctx->entity.file->handle_mutex); @@ -365,7 +369,7 @@ static int pcap_file_dispatch(struct pio_pcap_file_device_context *pfile_dev_ctx } int packet_q_len = nr_pkts; - int res = -1; + ssize_t res = -1; pthread_mutex_lock(&pfile_dev_ctx->entity.file->handle_mutex); res = pcap_dispatch(pfile_dev_ctx->entity.file->pcap_handle, packet_q_len, @@ -380,17 +384,19 @@ static int pcap_file_dispatch(struct pio_pcap_file_device_context *pfile_dev_ctx } else { // success struct pio_packet *p = nullptr; - int i = 0; + size_t i = 0; + uint32_t q_len = 0; pthread_mutex_lock(&pfile_dev_ctx->pkt_queues[rxq_id].mutex_q); do { p = pio_packet_dequeue(&pfile_dev_ctx->pkt_queues[rxq_id]); + q_len = pfile_dev_ctx->pkt_queues[rxq_id].len; pkts[i] = (struct stellar_packet *)p; i++; - } while (p != nullptr && (i < nr_pkts)); + } while ((q_len != 0) && (i < nr_pkts)); pthread_mutex_unlock(&pfile_dev_ctx->pkt_queues[rxq_id].mutex_q); - if (nullptr == p) { - res = i - 1; + if (q_len == 0) { + res = i; } else { res = nr_pkts; } @@ -399,10 +405,10 @@ static int pcap_file_dispatch(struct pio_pcap_file_device_context *pfile_dev_ctx return res; } -static int pcap_directory_get_modified_time(char *pfile, struct timespec *out) +static ssize_t pcap_directory_get_modified_time(char *pfile, struct timespec *out) { struct stat buf; - int ret = -1; + ssize_t ret = -1; if (nullptr == pfile) { return ret; @@ -443,7 +449,7 @@ find_pending_file_to_add(struct pio_pcap_file_device_context *pfile_dev_ctx, str } struct pending_file *file_to_add = CALLOC(struct pending_file, 1); - int ret = strncpy_safe(file_to_add->file_name, abs_path, sizeof(file_to_add->file_name)); + ssize_t ret = strncpy_safe(file_to_add->file_name, abs_path, sizeof(file_to_add->file_name)); if (ret < 0) { log_error(ST_ERR_STR_COPY, "file_to_add file name copy failed."); return nullptr; @@ -456,7 +462,7 @@ find_pending_file_to_add(struct pio_pcap_file_device_context *pfile_dev_ctx, str return file_to_add; } -static int pcap_directory_insert_file(struct pio_pcap_file_device_context *pfile_dev_ctx, struct pending_file *file_to_add) +static ssize_t pcap_directory_insert_file(struct pio_pcap_file_device_context *pfile_dev_ctx, struct pending_file *file_to_add) { if (nullptr == pfile_dev_ctx || file_to_add) { log_error(ST_ERR_PCAP_FILE_COLLECT_FAILED, "invalid directory or file parameters."); @@ -486,7 +492,7 @@ static int pcap_directory_insert_file(struct pio_pcap_file_device_context *pfile return 0; } -static int pcap_directory_collect_pending_files(struct pio_pcap_file_device_context *pfile_dev_ctx, struct timespec *deadline) +static ssize_t pcap_directory_collect_pending_files(struct pio_pcap_file_device_context *pfile_dev_ctx, struct timespec *deadline) { if (nullptr == pfile_dev_ctx) { return -1; @@ -526,10 +532,10 @@ static int pcap_directory_collect_pending_files(struct pio_pcap_file_device_cont return 0; } -static int pcap_directory_dispatch(struct pio_pcap_file_device_context *pfile_dev_ctx, uint16_t rxq_id, - struct stellar_packet **pkts, int nr_pkts) +static ssize_t pcap_directory_dispatch(struct pio_pcap_file_device_context *pfile_dev_ctx, uint32_t rxq_id, + struct stellar_packet **pkts, size_t nr_pkts) { - int res = -1; + ssize_t res = -1; struct timespec deadline; memset(&deadline, 0, sizeof(struct timespec)); @@ -611,7 +617,7 @@ static int pcap_directory_dispatch(struct pio_pcap_file_device_context *pfile_de return res; } -int pio_pcap_file_device_receive(struct packet_io_device *pdev, uint16_t rxq_id, struct stellar_packet **pkts, int nr_pkts) +ssize_t pio_pcap_file_device_receive(struct packet_io_device *pdev, uint32_t rxq_id, struct stellar_packet **pkts, size_t nr_pkts) { struct pio_pcap_file_device_context *pfile_dev_ctx = pdev->entity.pcap_file_dev_ctx; if (nullptr == pfile_dev_ctx) { @@ -619,7 +625,7 @@ int pio_pcap_file_device_receive(struct packet_io_device *pdev, uint16_t rxq_id, return -1; } - int res = -1; + ssize_t res = -1; if (pfile_dev_ctx->is_dir == 0) { log_info("Start reading file:%s", pfile_dev_ctx->entity.file->file_name); res = pcap_file_dispatch(pfile_dev_ctx, rxq_id, pkts, nr_pkts); @@ -631,15 +637,15 @@ int pio_pcap_file_device_receive(struct packet_io_device *pdev, uint16_t rxq_id, return res; } -void pio_pcap_file_device_pkt_free(__unused struct packet_io_device *pdev, __unused uint16_t qid, struct stellar_packet **pkts, int nr_pkts) +void pio_pcap_file_device_pkt_free(__unused struct packet_io_device *pdev, __unused uint32_t qid, struct stellar_packet **pkts, size_t nr_pkts) { - for (int i = 0; i < nr_pkts; i++) { + for (size_t i = 0; i < nr_pkts; i++) { struct pio_packet *p = (struct pio_packet *)pkts[i]; FREE(p); } } -int pio_pcap_file_instance_create(struct packet_io_instance *pinst) +ssize_t pio_pcap_file_instance_create(struct packet_io_instance *pinst) { if (nullptr == pinst) { log_error(ST_ERR_PIO_PCAP_FILE_INSTANCE, "invalid pcap file instance pointer."); @@ -661,34 +667,29 @@ void pio_pcap_file_instance_destroy(struct packet_io_instance *pinst) return; } - FREE(pinst->entity.pcap_file_inst_ctx); - - for (uint32_t i = 0; i < pinst->dev_cnt; i++) { - pio_pcap_file_device_close(pinst->devices[i]); - FREE(pinst->devices[i]); + if (pinst->entity.pcap_file_inst_ctx != nullptr) { + FREE(pinst->entity.pcap_file_inst_ctx); } + + struct packet_io_device *node = nullptr; + while ((node = TAILQ_FIRST(&pinst->device_queue_head)) != nullptr) { + TAILQ_REMOVE(&pinst->device_queue_head, node, next); + pinst->dev_cnt--; + pio_pcap_file_device_close(node); + FREE(node); + } } -void *pio_pcap_file_device_buff_ctrlzone(struct stellar_packet *p) +char *pio_pcap_file_device_buff_ctrlzone(struct stellar_packet *p, size_t *ctrlzone_len) { struct pio_packet *pkt = (struct pio_packet *)p; - return pkt->pkt_hdr; + *ctrlzone_len = CUSTOM_ZONE_LEN; + return (char *)pkt->pkt_hdr; } -char *pio_pcap_file_device_buff_mtod(struct stellar_packet *p) +char *pio_pcap_file_device_buff_mtod(struct stellar_packet *p, size_t *data_len) { struct pio_packet *pkt = (struct pio_packet *)p; + *data_len = pkt->pkt_len; return (char *)pkt->pkt_payload; -} - -uint32_t pio_pcap_file_device_buff_buflen(struct stellar_packet *p) -{ - struct pio_packet *pkt = (struct pio_packet *)p; - return (pkt->pkt_len + CUSTOM_ZONE_LEN); -} - -uint32_t pio_pcap_file_device_buff_datalen(struct stellar_packet *p) -{ - struct pio_packet *pkt = (struct pio_packet *)p; - return (pkt->pkt_len); -} +} \ No newline at end of file diff --git a/src/packet_io/pcap_file_mode/pio_pcap_file.h b/src/packet_io/pcap_file_mode/pio_pcap_file.h index e72781d..6bce0d9 100644 --- a/src/packet_io/pcap_file_mode/pio_pcap_file.h +++ b/src/packet_io/pcap_file_mode/pio_pcap_file.h @@ -21,7 +21,6 @@ extern "C" #include #include -#include "global_var.h" #include "packet_io_util.h" struct pio_pcap_file_instance_context { @@ -38,8 +37,8 @@ struct pcap_file_shared_info { /* bpf filter string, such as "tcp and port 25"*/ char bpf_string[STR_MAX_LEN]; - /* delete after the pcap file is read */ - bool should_delete; + /* if delete when pcapfile is processed */ + int should_delete; /* the timestamp of the last process */ struct timespec last_processed_ts; @@ -100,7 +99,7 @@ struct pio_pcap_file_device_context { struct pcap_file_shared_info shared; /* point to packet_io device it belongs to */ - struct packet_io_device *pio_dev; + struct packet_io_device *pdev; }; /** @@ -109,7 +108,7 @@ struct pio_pcap_file_device_context { * @param pinst * @return int */ -int pio_pcap_file_instance_create(struct packet_io_instance *pinst); +ssize_t pio_pcap_file_instance_create(struct packet_io_instance *pinst); /** * @brief @@ -126,24 +125,20 @@ void pio_pcap_file_instance_destroy(struct packet_io_instance *pinst); * pdev->rxq_num: number of the packet receiving queues for the device * pdev->txq_num: number of the packet sending queues for the device */ -int pio_pcap_file_device_open(struct packet_io_device *pdev); +ssize_t pio_pcap_file_device_open(struct packet_io_device *pdev); /** * @brief close pcap_live device */ -int pio_pcap_file_device_close(struct packet_io_device *pdev); +ssize_t pio_pcap_file_device_close(struct packet_io_device *pdev); -int pio_pcap_file_device_receive(struct packet_io_device *pdev, uint16_t rxq_id, struct stellar_packet **pkts, int nr_pkts); +ssize_t pio_pcap_file_device_receive(struct packet_io_device *pdev, uint32_t rxq_id, struct stellar_packet **pkts, size_t nr_pkts); -void pio_pcap_file_device_pkt_free(struct packet_io_device *pdev, uint16_t qid, struct stellar_packet **pkts, int nr_pkts); +void pio_pcap_file_device_pkt_free(struct packet_io_device *pdev, uint32_t qid, struct stellar_packet **pkts, size_t nr_pkts); -void *pio_pcap_file_device_buff_ctrlzone(struct stellar_packet *p); +char *pio_pcap_file_device_buff_ctrlzone(struct stellar_packet *p, size_t *ctrlzone_len); -char *pio_pcap_file_device_buff_mtod(struct stellar_packet *p); - -uint32_t pio_pcap_file_device_buff_buflen(struct stellar_packet *p); - -uint32_t pio_pcap_file_device_buff_datalen(struct stellar_packet *p); +char *pio_pcap_file_device_buff_mtod(struct stellar_packet *p, size_t *data_len); #ifdef __cpluscplus } diff --git a/src/packet_io/pcap_live_mode/pio_pcap_live.cpp b/src/packet_io/pcap_live_mode/pio_pcap_live.cpp index 73f6a72..0ccc804 100644 --- a/src/packet_io/pcap_live_mode/pio_pcap_live.cpp +++ b/src/packet_io/pcap_live_mode/pio_pcap_live.cpp @@ -18,11 +18,12 @@ #include "pio_pcap_live.h" #include "packet_io.h" #include "packet_io_util.h" +#include "packet_io_internal.h" #define DEFAULT_MAX_PACKET_SIZE 65535 #define TIMEOUT_MS 500 -static int pcap_live_init(struct pio_pcap_live_device_context *plive_dev_ctx, const char *dev_name) +static ssize_t pcap_live_init(struct pio_pcap_live_device_context *plive_dev_ctx, const char *dev_name) { if (nullptr == plive_dev_ctx) { return -1; @@ -36,14 +37,14 @@ static int pcap_live_init(struct pio_pcap_live_device_context *plive_dev_ctx, co return -1; } - if (g_engine_instance.config.packet_io.snaplen == 0) { + if (g_packet_io_config.pcap.snaplen == 0) { plive_dev_ctx->pcap_snaplen = DEFAULT_MAX_PACKET_SIZE; } else { - plive_dev_ctx->pcap_snaplen = g_engine_instance.config.packet_io.snaplen; + plive_dev_ctx->pcap_snaplen = g_packet_io_config.pcap.snaplen; } /* set snaplen */ - int res = pcap_set_snaplen(plive_dev_ctx->pcap_handle, plive_dev_ctx->pcap_snaplen); + ssize_t res = pcap_set_snaplen(plive_dev_ctx->pcap_handle, plive_dev_ctx->pcap_snaplen); if (res != 0) { log_error(ST_ERR_PCAP_SET_SNAPLEN, "could not set snaplen, error:%s", pcap_geterr(plive_dev_ctx->pcap_handle)); @@ -52,7 +53,7 @@ static int pcap_live_init(struct pio_pcap_live_device_context *plive_dev_ctx, co log_info("set snaplen to %d for %s", plive_dev_ctx->pcap_snaplen, dev_name); /* set promisc */ - res = pcap_set_promisc(plive_dev_ctx->pcap_handle, g_engine_instance.config.packet_io.promisc); + res = pcap_set_promisc(plive_dev_ctx->pcap_handle, g_packet_io_config.pcap.promisc); if (res != 0) { log_error(ST_ERR_PCAP_SET_PROMISC, "could not set promisc mode, error:%s", pcap_geterr(plive_dev_ctx->pcap_handle)); @@ -76,8 +77,8 @@ static int pcap_live_init(struct pio_pcap_live_device_context *plive_dev_ctx, co plive_dev_ctx->pcap_state = PCAP_STATE_UP; /* set bpf filter */ - if (strlen(g_engine_instance.config.packet_io.bpf_string) != 0) { - res = strncpy_safe(plive_dev_ctx->bpf_string, g_engine_instance.config.packet_io.bpf_string, + if (strlen(g_packet_io_config.pcap.bpf_string) != 0) { + res = strncpy_safe(plive_dev_ctx->bpf_string, g_packet_io_config.pcap.bpf_string, sizeof(plive_dev_ctx->bpf_string)); if (res < 0) { log_error(ST_ERR_STR_COPY, "plive_dev_ctx bpf string copy failed."); @@ -107,9 +108,9 @@ static int pcap_live_init(struct pio_pcap_live_device_context *plive_dev_ctx, co return res; } -int pio_pcap_live_device_open(struct packet_io_device *pdev) +ssize_t pio_pcap_live_device_open(struct packet_io_device *pdev) { - int res = -1; + ssize_t res = -1; if (nullptr == pdev) { log_error(ST_ERR_PIO_PCAP_LIVE_DEVICE, "invalid packet_io_device pointer."); @@ -124,7 +125,7 @@ int pio_pcap_live_device_open(struct packet_io_device *pdev) pthread_mutex_init(&pdev->entity.pcap_live_dev_ctx->handle_mutex, nullptr); - pdev->entity.pcap_live_dev_ctx->pio_dev = pdev; + pdev->entity.pcap_live_dev_ctx->pdev = pdev; res = pcap_live_init(pdev->entity.pcap_live_dev_ctx, pdev->dev_name); if (res < 0) { @@ -136,7 +137,7 @@ int pio_pcap_live_device_open(struct packet_io_device *pdev) return res; } -int pio_pcap_live_device_close(struct packet_io_device *pdev) +ssize_t pio_pcap_live_device_close(struct packet_io_device *pdev) { if (nullptr == pdev) { log_error(ST_ERR_PIO_PCAP_FILE_DEVICE, "invalid pdev pointer, so close pcap live device failed."); @@ -182,7 +183,7 @@ static void pcap_live_pkt_callback_oneshot(char *user, struct pcap_pkthdr *pkt_h } /* nr_rxq <= PKT_QUEUE_MAX_NUM */ - uint16_t nr_rxq = plive_dev_ctx->pio_dev->rxq_num; + uint16_t nr_rxq = plive_dev_ctx->pdev->rxq_num; uint16_t rxq_id = pio_packet_hash(p) % nr_rxq; /* hash to specific queue id and enqueue */ @@ -191,9 +192,9 @@ static void pcap_live_pkt_callback_oneshot(char *user, struct pcap_pkthdr *pkt_h pthread_mutex_unlock(&plive_dev_ctx->pkt_queues[rxq_id].mutex_q); } -int pio_pcap_live_device_receive(struct packet_io_device *pdev, uint16_t rxq_id, struct stellar_packet **pkts, int nr_pkts) +ssize_t pio_pcap_live_device_receive(struct packet_io_device *pdev, uint32_t rxq_id, struct stellar_packet **pkts, size_t nr_pkts) { - int res = -1; + ssize_t res = -1; struct pio_pcap_live_device_context *plive_dev_ctx = pdev->entity.pcap_live_dev_ctx; if (nullptr == plive_dev_ctx) { @@ -201,7 +202,7 @@ int pio_pcap_live_device_receive(struct packet_io_device *pdev, uint16_t rxq_id, return res; } - int packet_q_len = nr_pkts; + size_t packet_q_len = nr_pkts; pthread_mutex_lock(&plive_dev_ctx->handle_mutex); res = pcap_dispatch(plive_dev_ctx->pcap_handle, packet_q_len, (pcap_handler)pcap_live_pkt_callback_oneshot, (u_char *)plive_dev_ctx); @@ -213,17 +214,19 @@ int pio_pcap_live_device_receive(struct packet_io_device *pdev, uint16_t rxq_id, } else { struct pio_packet *p = nullptr; - int i = 0; + size_t i = 0; uint32_t q_len = 0; - pthread_mutex_lock(&plive_dev_ctx->pkt_queues[rxq_id].mutex_q); - do { - p = pio_packet_dequeue(&plive_dev_ctx->pkt_queues[rxq_id]); - q_len = plive_dev_ctx->pkt_queues[rxq_id].len; - pkts[i] = (struct stellar_packet *)p; - printf("rxq_id:%d, i:%d, pkts[i]:%p\n", rxq_id, i, pkts[i]); - i++; - } while ((q_len != 0) && (i < nr_pkts)); - pthread_mutex_unlock(&plive_dev_ctx->pkt_queues[rxq_id].mutex_q); + + if (plive_dev_ctx->pkt_queues[rxq_id].len > 0) { + pthread_mutex_lock(&plive_dev_ctx->pkt_queues[rxq_id].mutex_q); + do { + p = pio_packet_dequeue(&plive_dev_ctx->pkt_queues[rxq_id]); + q_len = plive_dev_ctx->pkt_queues[rxq_id].len; + pkts[i] = (struct stellar_packet *)p; + i++; + } while ((q_len != 0) && (i < nr_pkts)); + pthread_mutex_unlock(&plive_dev_ctx->pkt_queues[rxq_id].mutex_q); + } if (q_len == 0) { res = i; @@ -235,9 +238,9 @@ int pio_pcap_live_device_receive(struct packet_io_device *pdev, uint16_t rxq_id, return res; } -int pio_pcap_live_device_send(struct packet_io_device *pdev, uint16_t txq_id, struct stellar_packet **pkts, int nr_pkts) +ssize_t pio_pcap_live_device_send(struct packet_io_device *pdev, uint32_t txq_id, struct stellar_packet **pkts, size_t nr_pkts) { - int res = -1; + ssize_t res = -1; struct pio_pcap_live_device_context *plive_dev_ctx = pdev->entity.pcap_live_dev_ctx; if (nullptr == plive_dev_ctx) { @@ -246,7 +249,7 @@ int pio_pcap_live_device_send(struct packet_io_device *pdev, uint16_t txq_id, st } pthread_mutex_lock(&plive_dev_ctx->handle_mutex); - for (int i = 0; i < nr_pkts; i++) { + for (size_t i = 0; i < nr_pkts; i++) { struct pio_packet *p = (struct pio_packet *)pkts[i]; res = pcap_sendpacket(plive_dev_ctx->pcap_handle, (u_char *)p->pkt_payload, p->pkt_len); } @@ -256,17 +259,15 @@ int pio_pcap_live_device_send(struct packet_io_device *pdev, uint16_t txq_id, st return 0; } -void pio_pcap_live_device_pkt_free(__unused struct packet_io_device *pdev, __unused uint16_t qid, struct stellar_packet **pkts, int nr_pkts) +void pio_pcap_live_device_pkt_free(__unused struct packet_io_device *pdev, __unused uint32_t qid, struct stellar_packet **pkts, size_t nr_pkts) { void **pptr_pkts = (void **)pkts; - for (int i = 0; i < nr_pkts; i++) { - printf("before free pptr_pkts[%d]:%p\n", i, pptr_pkts[i]); + for (size_t i = 0; i < nr_pkts; i++) { FREE(pptr_pkts[i]); - printf("after free pptr_pkts[%d]:%p\n", i, pptr_pkts[i]); } } -int pio_pcap_live_instance_create(struct packet_io_instance *pinst) +ssize_t pio_pcap_live_instance_create(struct packet_io_instance *pinst) { if (nullptr == pinst) { log_error(ST_ERR_PIO_PCAP_LIVE_INSTANCE, "invalid pcap live instance pointer."); @@ -290,32 +291,25 @@ void pio_pcap_live_instance_destroy(struct packet_io_instance *pinst) FREE(pinst->entity.pcap_live_inst_ctx); - for (uint32_t i = 0; i < pinst->dev_cnt; i++) { - pio_pcap_live_device_close(pinst->devices[i]); - FREE(pinst->devices[i]); - } + struct packet_io_device *node = nullptr; + while ((node = TAILQ_FIRST(&pinst->device_queue_head)) != nullptr) { + TAILQ_REMOVE(&pinst->device_queue_head, node, next); + pinst->dev_cnt--; + pio_pcap_live_device_close(node); + FREE(node); + } } -void *pio_pcap_live_device_buff_ctrlzone(struct stellar_packet *p) +char *pio_pcap_live_device_buff_ctrlzone(struct stellar_packet *p, size_t *ctrlzone_len) { struct pio_packet *pkt = (struct pio_packet *)p; - return pkt->pkt_hdr; + *ctrlzone_len = CUSTOM_ZONE_LEN; + return (char *)pkt->pkt_hdr; } -char *pio_pcap_live_device_buff_mtod(struct stellar_packet *p) +char *pio_pcap_live_device_buff_mtod(struct stellar_packet *p, size_t *data_len) { struct pio_packet *pkt = (struct pio_packet *)p; + *data_len = pkt->pkt_len; return (char *)pkt->pkt_payload; -} - -uint32_t pio_pcap_live_device_buff_buflen(struct stellar_packet *p) -{ - struct pio_packet *pkt = (struct pio_packet *)p; - return (pkt->pkt_len + CUSTOM_ZONE_LEN); -} - -uint32_t pio_pcap_live_device_buff_datalen(struct stellar_packet *p) -{ - struct pio_packet *pkt = (struct pio_packet *)p; - return (pkt->pkt_len); -} +} \ No newline at end of file diff --git a/src/packet_io/pcap_live_mode/pio_pcap_live.h b/src/packet_io/pcap_live_mode/pio_pcap_live.h index 6e0e9bb..ed89e4b 100644 --- a/src/packet_io/pcap_live_mode/pio_pcap_live.h +++ b/src/packet_io/pcap_live_mode/pio_pcap_live.h @@ -19,7 +19,6 @@ extern "C" #include #include -#include "global_var.h" #include "packet_io_util.h" #define PCAP_STATE_UP 1 @@ -59,7 +58,7 @@ struct pio_pcap_live_device_context { /* rx packet queue */ struct pio_packet_queue pkt_queues[PKT_QUEUE_MAX_NUM]; - struct packet_io_device *pio_dev; + struct packet_io_device *pdev; }; /** @@ -69,7 +68,7 @@ struct pio_pcap_live_device_context { * @param wrk_thread_num * @return int */ -int pio_pcap_live_instance_create(struct packet_io_instance *pinst); +ssize_t pio_pcap_live_instance_create(struct packet_io_instance *pinst); /** * @brief @@ -86,26 +85,22 @@ void pio_pcap_live_instance_destroy(struct packet_io_instance *pinst); * pdev->rxq_num: number of the packet receiving queues for the device * pdev->txq_num: number of the packet sending queues for the device */ -int pio_pcap_live_device_open(struct packet_io_device *pdev); +ssize_t pio_pcap_live_device_open(struct packet_io_device *pdev); /** * @brief close pcap_live device */ -int pio_pcap_live_device_close(struct packet_io_device *pdev); +ssize_t pio_pcap_live_device_close(struct packet_io_device *pdev); -int pio_pcap_live_device_receive(struct packet_io_device *pdev, uint16_t rxq_id, struct stellar_packet **pkts, int nr_pkts); +ssize_t pio_pcap_live_device_receive(struct packet_io_device *pdev, uint32_t rxq_id, struct stellar_packet **pkts, size_t nr_pkts); -int pio_pcap_live_device_send(struct packet_io_device *pdev, uint16_t txq_id, struct stellar_packet **pkts, int nr_pkts); +ssize_t pio_pcap_live_device_send(struct packet_io_device *pdev, uint32_t txq_id, struct stellar_packet **pkts, size_t nr_pkts); -void pio_pcap_live_device_pkt_free(struct packet_io_device *pdev, uint16_t qid, struct stellar_packet **pkts, int nr_pkts); +void pio_pcap_live_device_pkt_free(struct packet_io_device *pdev, uint32_t qid, struct stellar_packet **pkts, size_t nr_pkts); -void *pio_pcap_live_device_buff_ctrlzone(struct stellar_packet *p); +char *pio_pcap_live_device_buff_ctrlzone(struct stellar_packet *p, size_t *ctrlzone_len); -char *pio_pcap_live_device_buff_mtod(struct stellar_packet *p); - -uint32_t pio_pcap_live_device_buff_buflen(struct stellar_packet *p); - -uint32_t pio_pcap_live_device_buff_datalen(struct stellar_packet *p); +char *pio_pcap_live_device_buff_mtod(struct stellar_packet *p, size_t *data_len); #ifdef __cpluscplus } diff --git a/src/packet_io/test/CMakeLists.txt b/src/packet_io/test/CMakeLists.txt index 949e697..e5ff651 100644 --- a/src/packet_io/test/CMakeLists.txt +++ b/src/packet_io/test/CMakeLists.txt @@ -8,6 +8,7 @@ target_link_libraries( packet_io dl pcap + toml ) include(GoogleTest) diff --git a/src/packet_io/test/gtest_packet_io.cpp b/src/packet_io/test/gtest_packet_io.cpp index 70ccff4..97993d8 100644 --- a/src/packet_io/test/gtest_packet_io.cpp +++ b/src/packet_io/test/gtest_packet_io.cpp @@ -1,15 +1,275 @@ #include +#include "utils.h" +#include "packet.h" #include "packet_io.h" +#include "packet_io_util.h" -TEST(PACKET_IO_Test, packet_io_instance_create) { - struct packet_io_instance *ppio_inst = packet_io_instance_create("stellar", PACKET_IO_RUN_MODE_PCAP_FILE); - EXPECT_NE(ppio_inst, nullptr); +TEST(PACKET_IO_Test, packet_io_instance_create_and_destroy) { + struct packet_io_instance *ppio_inst = packet_io_instance_create(nullptr, PACKET_IO_RUN_MODE_PCAP_FILE); + EXPECT_EQ(ppio_inst, nullptr); + ppio_inst = packet_io_instance_create("stellar", PACKET_IO_RUN_MODE_MAX); + EXPECT_EQ(ppio_inst, nullptr); + ppio_inst = packet_io_instance_create("stellar", PACKET_IO_RUN_MODE_PCAP_FILE); + EXPECT_NE(ppio_inst, nullptr); + packet_io_fini(ppio_inst); } -TEST(PACKET_IO_Test, packet_io_open_device) { +TEST(PACKET_IO_Test, packet_io_device_open_and_close) { + struct packet_io_device *pdev = packet_io_device_open(nullptr, nullptr, 1, 1); + EXPECT_EQ(pdev, nullptr); + struct packet_io_instance *ppio_inst = packet_io_instance_create("stellar", PACKET_IO_RUN_MODE_PCAP_LIVE); + EXPECT_NE(ppio_inst, nullptr); + pdev = packet_io_device_open(ppio_inst, nullptr, 1, 1); + EXPECT_EQ(pdev, nullptr); + pdev = packet_io_device_open(ppio_inst, "lo", 1, 1); + EXPECT_NE(pdev, nullptr); + packet_io_device_close(pdev); + packet_io_fini(ppio_inst); +} + +TEST(PACKET_IO_Test, packet_io_device_rx) { struct packet_io_instance *ppio_inst = packet_io_instance_create("stellar", PACKET_IO_RUN_MODE_PCAP_FILE); - EXPECT_EQ(packet_io_device_open(ppio_inst, NULL, 1, 1), nullptr); + struct packet_io_device *pdev = packet_io_device_open(ppio_inst, "./src/packet_io/test/test-64.pcapng", 1, 1); + EXPECT_NE(pdev, nullptr); + struct stellar_packet *rx_pkts[64]; + ssize_t fetch_num = packet_io_device_rx(pdev, 0, rx_pkts, 1); + EXPECT_EQ(fetch_num, 1); + packet_io_device_close(pdev); + packet_io_fini(ppio_inst); +} + +TEST(PACKET_IO_Test, packet_io_device_tx) { + struct packet_io_instance *ppio_inst = packet_io_instance_create("stellar", PACKET_IO_RUN_MODE_PCAP_LIVE); + struct packet_io_device *pdev = packet_io_device_open(ppio_inst, "lo", 1, 1); + EXPECT_NE(pdev, nullptr); + struct stellar_packet *rx_pkts[64]; + ssize_t send_num = packet_io_device_tx(pdev, 0, rx_pkts, 1); + EXPECT_EQ(send_num, 0); + packet_io_device_close(pdev); + packet_io_fini(ppio_inst); +} + +TEST(PACKET_IO_Test, packet_io_pkts_free) { + struct packet_io_instance *ppio_inst = packet_io_instance_create("stellar", PACKET_IO_RUN_MODE_PCAP_FILE); + struct packet_io_device *pdev = packet_io_device_open(ppio_inst, "./src/packet_io/test/test-64.pcapng", 1, 1); + EXPECT_NE(pdev, nullptr); + struct stellar_packet *rx_pkts[64]; + ssize_t fetch_num = packet_io_device_rx(pdev, 0, rx_pkts, 1); + EXPECT_EQ(fetch_num, 1); + packet_io_pkts_free(pdev, 0, rx_pkts, 1); + packet_io_device_close(pdev); + packet_io_fini(ppio_inst); +} + +TEST(PACKET_IO_Test, get_stellar_packet_ctrlzone) { + struct packet_io_instance *ppio_inst = packet_io_instance_create("stellar", PACKET_IO_RUN_MODE_PCAP_FILE); + struct packet_io_device *pdev = packet_io_device_open(ppio_inst, "./src/packet_io/test/test-64.pcapng", 1, 1); + EXPECT_NE(pdev, nullptr); + struct stellar_packet *rx_pkts[64]; + ssize_t fetch_num = packet_io_device_rx(pdev, 0, rx_pkts, 1); + EXPECT_EQ(fetch_num, 1); + size_t ctrlzone_len = 0; + void *buff_ctrlzone = get_stellar_packet_ctrlzone(rx_pkts[0], &ctrlzone_len); + EXPECT_EQ(buff_ctrlzone, rx_pkts[0]); + + packet_io_pkts_free(pdev, 0, rx_pkts, 1); + packet_io_device_close(pdev); + packet_io_fini(ppio_inst); +} + +TEST(PACKET_IO_Test, get_stellar_packet_data) { + struct packet_io_instance *ppio_inst = packet_io_instance_create("stellar", PACKET_IO_RUN_MODE_PCAP_FILE); + struct packet_io_device *pdev = packet_io_device_open(ppio_inst, "./src/packet_io/test/test-64.pcapng", 1, 1); + EXPECT_NE(pdev, nullptr); + struct stellar_packet *rx_pkts[64]; + ssize_t fetch_num = packet_io_device_rx(pdev, 0, rx_pkts, 1); + EXPECT_EQ(fetch_num, 1); + size_t data_len = 0; + void *buff_ctrlzone = get_stellar_packet_data(rx_pkts[0], &data_len); + EXPECT_EQ(buff_ctrlzone, (uint8_t *)rx_pkts[0]+64); + + packet_io_pkts_free(pdev, 0, rx_pkts, 1); + packet_io_device_close(pdev); + packet_io_fini(ppio_inst); +} + +TEST(PACKET_IO_UTIL_Test, strncpy_safe) { + ssize_t res = strncpy_safe(nullptr, nullptr, 0); + EXPECT_EQ(res, -1); + + char dst[5]; + res = strncpy_safe(dst, "hello", sizeof(dst)); + EXPECT_STREQ(dst, "hell"); + EXPECT_EQ(res, 0); + + memset(dst, 0, sizeof(dst)); + res = strncpy_safe(dst, "he", sizeof(dst)); + EXPECT_STREQ(dst, "he"); + EXPECT_EQ(res, 0); +} + +TEST(PACKET_IO_UTIL_Test, packet_copy_data) { + uint8_t dst[5]; + uint8_t src[4] = {0x12, 0x34, 0x56, 0x78}; + ssize_t res = packet_copy_data(dst, src, sizeof(src)); + EXPECT_EQ(res, 0); + EXPECT_EQ(dst[0], 0x12); + EXPECT_EQ(dst[1], 0x34); + EXPECT_EQ(dst[2], 0x56); + EXPECT_EQ(dst[3], 0x78); +} + +TEST(PACKET_IO_UTIL_Test, pio_packet_hash) { + struct pio_packet *p = (struct pio_packet *)malloc(MAX_SIZE_OF_PIO_PACKET); + memset(p, 0, MAX_SIZE_OF_PIO_PACKET); + uint64_t res = pio_packet_hash(p); + EXPECT_EQ(res, 0); + FREE(p); +} + +TEST(PACKET_IO_UTIL_Test, pio_packet_queue_init) { + +} + +TEST(PACKET_IO_UTIL_Test, pio_packet_enqueue) { + +} + +TEST(PACKET_IO_UTIL_Test, pio_packet_dequeue) { + +} + +TEST(PACKET_IO_UTIL_Test, release_pio_packet_queue) { + +} + +TEST(PACKET_IO_PIO_MARSIO_Test, pio_marsio_instance_create) { + +} + +TEST(PACKET_IO_PIO_MARSIO_Test, pio_marsio_instance_destroy) { + +} + +TEST(PACKET_IO_PIO_MARSIO_Test, pio_marsio_device_open) { + +} + +TEST(PACKET_IO_PIO_MARSIO_Test, pio_marsio_device_close) { + +} + +TEST(PACKET_IO_PIO_MARSIO_Test, pio_marsio_device_receive) { + +} + +TEST(PACKET_IO_PIO_MARSIO_Test, pio_marsio_device_send) { + +} + +TEST(PACKET_IO_PIO_MARSIO_Test, pio_marsio_device_pkt_free) { + +} + +TEST(PACKET_IO_PIO_MARSIO_Test, pio_marsio_device_buff_ctrlzone) { + +} + +TEST(PACKET_IO_PIO_MARSIO_Test, pio_marsio_device_buff_mtod) { + +} + +TEST(PACKET_IO_PIO_MARSIO_Test, pio_marsio_device_buff_buflen) { + +} + +TEST(PACKET_IO_PIO_MARSIO_Test, pio_marsio_device_buff_datalen) { + +} + +TEST(PACKET_IO_PIO_PCAP_FILE_Test, pio_pcap_file_instance_create) { + +} + +TEST(PACKET_IO_PIO_PCAP_FILE_Test, pio_pcap_file_instance_destroy) { + +} + +TEST(PACKET_IO_PIO_PCAP_FILE_Test, pio_pcap_file_device_open) { + +} + +TEST(PACKET_IO_PIO_PCAP_FILE_Test, pio_pcap_file_device_close) { + +} + +TEST(PACKET_IO_PIO_PCAP_FILE_Test, pio_pcap_file_device_receive) { + +} + +TEST(PACKET_IO_PIO_PCAP_FILE_Test, pio_pcap_file_device_pkt_free) { + +} + +TEST(PACKET_IO_PIO_PCAP_FILE_Test, pio_pcap_file_device_buff_ctrlzone) { + +} + +TEST(PACKET_IO_PIO_PCAP_FILE_Test, pio_pcap_file_device_buff_mtod) { + +} + +TEST(PACKET_IO_PIO_PCAP_FILE_Test, pio_pcap_file_device_buff_buflen) { + +} + +TEST(PACKET_IO_PIO_PCAP_FILE_Test, pio_pcap_file_device_buff_datalen) { + +} + +TEST(PACKET_IO_PIO_PCAP_LIVE_Test, pio_pcap_live_instance_create) { + +} + +TEST(PACKET_IO_PIO_PCAP_LIVE_Test, pio_pcap_live_instance_destroy) { + +} + +TEST(PACKET_IO_PIO_PCAP_LIVE_Test, pio_pcap_live_device_open) { + +} + +TEST(PACKET_IO_PIO_PCAP_LIVE_Test, pio_pcap_live_device_close) { + +} + +TEST(PACKET_IO_PIO_PCAP_LIVE_Test, pio_pcap_live_device_receive) { + +} + +TEST(PACKET_IO_PIO_PCAP_LIVE_Test, pio_pcap_live_device_send) { + +} + +TEST(PACKET_IO_PIO_PCAP_LIVE_Test, pio_pcap_live_device_pkt_free) { + +} + +TEST(PACKET_IO_PIO_PCAP_LIVE_Test, pio_pcap_live_device_buff_ctrlzone) { + +} + +TEST(PACKET_IO_PIO_PCAP_LIVE_Test, pio_pcap_live_device_buff_mtod) { + +} + +TEST(PACKET_IO_PIO_PCAP_LIVE_Test, pio_pcap_live_device_buff_buflen) { + +} + +TEST(PACKET_IO_PIO_PCAP_LIVE_Test, pio_pcap_live_device_buff_datalen) { + } int main(int argc, char ** argv) diff --git a/src/packet_io/test/test-64.pcapng b/src/packet_io/test/test-64.pcapng new file mode 100644 index 0000000000000000000000000000000000000000..eb87132d8602ca639a8f3cefe44e9376cc8c3dae GIT binary patch literal 25668 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