diff options
| author | 陆秋文 <[email protected]> | 2024-07-15 09:48:50 +0000 |
|---|---|---|
| committer | 陆秋文 <[email protected]> | 2024-07-15 09:48:50 +0000 |
| commit | f0e50964001c56042150c9c49284bf0aaa531a7c (patch) | |
| tree | dd15b7248485ecade179524a7670630f21be68ff | |
| parent | 24f4ab0940ef3652908b3a5968527951c53f66b8 (diff) | |
Feature mock api by cmocka
28 files changed, 1575 insertions, 127 deletions
diff --git a/.clang-format b/.clang-format index 33f943d..bea9245 100644 --- a/.clang-format +++ b/.clang-format @@ -2,6 +2,7 @@ BasedOnStyle: Microsoft PointerAlignment: Middle IndentExternBlock: NoIndent +PenaltyBreakAssignment: 100 # AccessModifierOffset: -4 # AlignAfterOpenBracket: DontAlign # AlignConsecutiveAssignments: false diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index 3941080..6bdb576 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -1,6 +1,6 @@ find_package(SYSTEMD REQUIRED) include_directories(${CMAKE_SOURCE_DIR}/include) -include_directories(${CMAKE_SOURCE_DIR}/include/extern) +include_directories(${CMAKE_SOURCE_DIR}/include/external) include_directories(${CMAKE_SOURCE_DIR}/include/internal) include_directories(include) @@ -18,3 +18,48 @@ target_include_directories(marsio INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}/include target_include_directories(marsio INTERFACE ${SYSTEMD_INCLUDE_DIRS}) install(TARGETS marsio LIBRARY DESTINATION ${MR_INSTALL_LIBDIR} COMPONENT Program) + + +################################################################################ +### unittests ################################################################## + +add_executable(test_marsio_rawio_api test/test_marsio_rawio_api.c src/marsio.c src/rawio.c src/mrb.c + src/sendpath.c src/monit.c src/tap.c src/dp_trace.c) + +target_link_libraries(test_marsio_rawio_api libcmocka libdpdk pthread infra elf z dl rt MESA_prof_load_static MESA_htable_static) + +target_include_directories(test_marsio_rawio_api PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include) +target_include_directories(test_marsio_rawio_api PRIVATE ${CMAKE_SOURCE_DIR}/include/external) +target_include_directories(test_marsio_rawio_api PRIVATE ${CMAKE_SOURCE_DIR}/include/internal) +target_include_directories(test_marsio_rawio_api PRIVATE ${CMAKE_SOURCE_DIR}/infra/include) +target_link_libraries(test_marsio_rawio_api -Wl,--wrap=vnode_mirror_enqueue_bulk) +target_link_libraries(test_marsio_rawio_api -Wl,--wrap=vnode_mirror_dequeue_burst) +target_link_libraries(test_marsio_rawio_api -Wl,--wrap=vnode_mirror_rt_object_retrieve) +target_link_libraries(test_marsio_rawio_api -Wl,--wrap=marsio_open_device) +target_link_libraries(test_marsio_rawio_api -Wl,--wrap=marsio_close_device) +target_link_libraries(test_marsio_rawio_api -Wl,--wrap=marsio_buff_free_v2) +target_link_libraries(test_marsio_rawio_api -Wl,--wrap=marsio_dp_trace_measurements_can_emit) +target_link_libraries(test_marsio_rawio_api -Wl,--wrap=marsio_buff_do_rehash) + +add_test(NAME test_marsio_rawio_api COMMAND test_marsio_rawio_api) + +################################################################################ +add_executable(test_marsio_instance_api test/test_marsio_instance_api.c src/marsio.c src/rawio.c src/mrb.c + src/sendpath.c src/monit.c src/tap.c src/dp_trace.c) + +target_link_libraries(test_marsio_instance_api libcmocka libdpdk pthread infra elf z dl rt MESA_prof_load_static MESA_htable_static) +target_include_directories(test_marsio_instance_api PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include) +target_include_directories(test_marsio_instance_api PRIVATE ${CMAKE_SOURCE_DIR}/include/external) +target_include_directories(test_marsio_instance_api PRIVATE ${CMAKE_SOURCE_DIR}/include/internal) +target_include_directories(test_marsio_instance_api PRIVATE ${CMAKE_SOURCE_DIR}/infra/include) +target_link_libraries(test_marsio_instance_api -Wl,--wrap=rte_eal_init) +target_link_libraries(test_marsio_instance_api -Wl,--wrap=rte_exit) +target_link_libraries(test_marsio_instance_api -Wl,--wrap=rte_mp_request_sync) + +#target_link_libraries(test_marsio_rawio_api -Wl,--wrap=vnode_mirror_dequeue_burst) +#target_link_libraries(test_marsio_rawio_api -Wl,--wrap=vnode_mirror_rt_object_retrieve) +#target_link_libraries(test_marsio_rawio_api -Wl,--wrap=marsio_open_device) +#target_link_libraries(test_marsio_rawio_api -Wl,--wrap=marsio_close_device) +#target_link_libraries(test_marsio_rawio_api -Wl,--wrap=marsio_buff_free_v2) +#target_link_libraries(test_marsio_rawio_api -Wl,--wrap=marsio_dp_trace_measurements_can_emit) +#target_link_libraries(test_marsio_rawio_api -Wl,--wrap=marsio_buff_do_rehash)
\ No newline at end of file diff --git a/app/include/mrapp.h b/app/include/mrapp.h index 0ea11bb..a81285e 100644 --- a/app/include/mrapp.h +++ b/app/include/mrapp.h @@ -1,6 +1,4 @@ #pragma once - -#include "dp_trace.h" #include <common.h> #include <ldbc.h> #include <marsio.h> @@ -11,6 +9,7 @@ #include <vdev_define.h> struct mr_instance; +struct dp_trace_process; struct mrapp_stat { diff --git a/app/src/dp_trace.c b/app/src/dp_trace.c index 361da17..55911d7 100644 --- a/app/src/dp_trace.c +++ b/app/src/dp_trace.c @@ -12,6 +12,7 @@ #include <sys/stat.h> #include <sys/utsname.h> #include <unistd.h> +#include <dp_trace.h> extern __thread struct mr_thread_info thread_info; @@ -19,7 +20,10 @@ int marsio_dp_trace_init(struct mr_instance * mr_instance) { mr_instance->trace = dp_trace_process_create(DP_TRACE_PROCESS_APP); if (mr_instance->trace == NULL) + { return RT_ERR; + } + return RT_SUCCESS; } @@ -93,6 +97,11 @@ cJSON * marsio_dp_trace_monit_loop(struct mr_instance * instance) cJSON * json_root = cJSON_CreateObject(); struct dp_trace_process * trace = instance->trace; + if (trace == NULL) + { + return json_root; + } + struct dp_trace_stat monit_statistics = {}; uint64_t filter_exec_hit = 0; diff --git a/app/src/marsio.c b/app/src/marsio.c index f61d935..8ae6a35 100644 --- a/app/src/marsio.c +++ b/app/src/marsio.c @@ -153,13 +153,15 @@ static void mrapp_rx_notify_init(struct mr_instance * instance) } /* EAL环境初始化 */ -static void mrapp_eal_init(struct mr_instance * instance) +static int mrapp_eal_init(struct mr_instance * instance) { char * eal_argv[MR_LIB_MAX_EAL_ARGC]; unsigned int eal_argc = 0; if (g_eal_inited > 0) - return; + { + return 0; + } WRITE_ARG(instance->appsym); WRITE_ARG("-c"); @@ -167,8 +169,8 @@ static void mrapp_eal_init(struct mr_instance * instance) WRITE_ARG("--proc-type=secondary"); char str_virtaddr[MR_STRING_MAX]; - int ret = - MESA_load_profile_string_nodef(instance->g_cfgfile_path, "eal", "virtaddr", str_virtaddr, sizeof(str_virtaddr)); + int ret = MESA_load_profile_string_nodef(instance->g_cfgfile_path, "eal", "virtaddr", str_virtaddr, + sizeof(str_virtaddr)); if (ret >= 0) { @@ -224,20 +226,35 @@ static void mrapp_eal_init(struct mr_instance * instance) /* 获得当前线程的亲和性设置,EAL初始化后恢复,避免从此线程派生的 线程全部带有EAL设置的亲和性。 */ - cpu_set_t __cpu_set; - ret = pthread_getaffinity_np(pthread_self(), sizeof(cpu_set_t), &__cpu_set); - MR_VERIFY_2(ret >= 0, "Cannot get init thread affinity: %s", strerror(errno)); + cpu_set_t _cpu_set; + ret = pthread_getaffinity_np(pthread_self(), sizeof(cpu_set_t), &_cpu_set); + if (unlikely(ret < 0)) + { + MR_ERROR("Cannot get init thread affinity: %s", strerror(errno)); + goto errout; + } rte_openlog_stream(stderr); - ret = rte_eal_init(eal_argc, eal_argv); - MR_VERIFY_2(ret >= 0, "Cannot init EAL Enviorment, Failed"); + ret = rte_eal_init((int)eal_argc, eal_argv); + if (unlikely(ret < 0)) + { + MR_ERROR("Cannot init EAL environment, Failed."); + goto errout; + } - ret = pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &__cpu_set); - MR_VERIFY_2(ret >= 0, "Cannot set init thread affinity: %s", strerror(errno)); + ret = pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &_cpu_set); + if (unlikely(ret < 0)) + { + MR_ERROR("Cannot set init thread affinity: %s", strerror(errno)); + goto errout; + } /* EAL环境初始化成功 */ g_eal_inited = 1; - return; + return 0; + +errout: + return -1; } struct app_register_req * app_register_request_construct(struct mr_instance * instance) @@ -290,16 +307,15 @@ void * marsio_survival_monitor(void * arg) int send_register_request(struct app_register_req * reg_req) { - int ret; int socket_pair[2]; - ret = socketpair(AF_UNIX, SOCK_STREAM, 0, socket_pair); + int ret = socketpair(AF_UNIX, SOCK_STREAM, 0, socket_pair); if (ret < 0) { MR_WARNING("Failed to create socketpair"); return RT_ERR; } - struct rte_mp_reply mp_reply; + struct rte_mp_reply mp_reply = {}; const struct timespec wait_timespec = { .tv_nsec = 0, .tv_sec = 30, @@ -314,6 +330,7 @@ int send_register_request(struct app_register_req * reg_req) reg_msg.num_fds = 1; reg_msg.len_param = sizeof(ptr_address); memcpy(reg_msg.param, &ptr_address, sizeof(ptr_address)); + ret = rte_mp_request_sync(®_msg, &mp_reply, &wait_timespec); if (ret < 0) { @@ -335,6 +352,7 @@ int send_register_request(struct app_register_req * reg_req) // Make sure the socket_pair[0] of the main process is closed and the kernel sends EOF _current_instance->marsio_fd = socket_pair[1]; close(socket_pair[0]); + pthread_t __pid = 0; ret = pthread_create(&__pid, NULL, marsio_survival_monitor, NULL); if (ret < 0) @@ -343,15 +361,23 @@ int send_register_request(struct app_register_req * reg_req) goto error; } - free(mp_reply.msgs); - FREE(reg_req); - FREE(rep_msg); + if (mp_reply.msgs != NULL) + { + free(mp_reply.msgs); + } + + rte_free(reg_req); + rte_free(rep_msg); return RT_SUCCESS; error: - free(mp_reply.msgs); - FREE(reg_req); - FREE(rep_msg); + if (mp_reply.msgs != NULL) + { + free(mp_reply.msgs); + } + + rte_free(reg_req); + rte_free(rep_msg); close(socket_pair[0]); close(socket_pair[1]); return RT_ERR; @@ -737,13 +763,19 @@ int marsio_init(struct mr_instance * instance, const char * appsym) goto err; } - mrapp_eal_init(instance); + if (mrapp_eal_init(instance) != RT_SUCCESS) + { + MR_ERROR("EAL initialization failed, recheck mrzcpd is running."); + goto err; + } +#if 0 if (marsio_dp_trace_init(instance) != RT_SUCCESS) { MR_ERROR("data path instance get failed, recheck mrzcpd is running."); goto err; } +#endif if (mrapp_register(instance) != RT_SUCCESS) { @@ -776,7 +808,10 @@ int marsio_init(struct mr_instance * instance, const char * appsym) err: if (instance->is_exit_when_err_raise) + { exit(EXIT_FAILURE); + } + return RT_ERR; } @@ -833,7 +868,10 @@ int marsio_thread_init(struct mr_instance * instance) out: pthread_mutex_unlock(&instance->lock_thread_init); if (ret < 0 && instance->is_exit_when_err_raise) + { exit(EXIT_FAILURE); + } + return ret; } diff --git a/app/src/mrb.c b/app/src/mrb.c index fe2a3ea..ea852c3 100644 --- a/app/src/mrb.c +++ b/app/src/mrb.c @@ -5,6 +5,7 @@ #include <mrb_define.h> #include <mrdp_trace.h> #include <protect.h> +#include <dp_trace.h> #include <rte_common.h> #include <rte_malloc.h> diff --git a/app/src/rawio.c b/app/src/rawio.c index 427534c..b4f3bc4 100644 --- a/app/src/rawio.c +++ b/app/src/rawio.c @@ -57,7 +57,6 @@ int mrapp_packet_fast_send_burst(struct mr_instance * instance, struct vdev_inst int marsio_recv_burst(struct mr_vdev * vdev, queue_id_t qid, marsio_buff_t * mbufs[], int nr_mbufs) { - assert(qid < vdev->nr_rxstream); if (unlikely(qid >= vdev->nr_rxstream)) return -EINVAL; @@ -214,11 +213,8 @@ int marsio_send_burst_with_options(struct mr_sendpath * sendpath, queue_id_t sid struct rte_mbuf ** _mbufs = (struct rte_mbuf **)mbufs; PROTECT_rte_mbuf_unpoison_bulk(_mbufs, nr_mbufs); - assert(sid < sendpath->target_vdi->nr_txstream); - for (int i = 0; i < nr_mbufs; i++) { - assert(_mbufs[i]->data_len != 0 && _mbufs[i]->pkt_len != 0); __rte_mbuf_sanity_check(mbufs[i], i); } diff --git a/app/test/test_marsio_instance_api.c b/app/test/test_marsio_instance_api.c new file mode 100644 index 0000000..301507a --- /dev/null +++ b/app/test/test_marsio_instance_api.c @@ -0,0 +1,356 @@ +#include <stdarg.h> +#include <stddef.h> +#include <stdint.h> +#include <setjmp.h> +#include <stdint.h> +#include <unistd.h> +#include <sys/stat.h> + +#include <rte_mbuf.h> +#include <rte_mempool.h> +#include <rte_eal.h> +#include <cmocka.h> +#include <marsio.h> + +#include <mr_rte_msg.h> + +extern int __real_rte_eal_init(int argc, char **argv); + +int __wrap_rte_eal_init(int argc, char * argv[]) +{ + int inject_eal_init_failed = mock_type(int); + if (inject_eal_init_failed) + { + return -1; + } + + return 0; +} + +static int rte_exit_called = 0; +int __wrap_rte_exit(int status) +{ + rte_exit_called = 1; + return 0; +} + +static int call_real_rte_mp_request_sync = 1; +extern int __real_rte_mp_request_sync(struct rte_mp_msg *req, struct rte_mp_reply *reply, + const struct timespec *ts); + +int __wrap_rte_mp_request_sync(struct rte_mp_msg *req, struct rte_mp_reply *reply, + const struct timespec *ts) +{ + if (call_real_rte_mp_request_sync) + { + return __real_rte_mp_request_sync(req, reply, ts); + } + + int mock_ret = mock_type(int); + if (mock_ret != 0) + { + return mock_ret; + } + + struct rte_mp_msg * mock_out_req = mock_ptr_type(struct rte_mp_msg *); + if (strcasecmp(req->name, "instance_alive_register") == 0) + { + struct app_register_resp * mock_resp = rte_zmalloc(NULL, sizeof(struct app_register_resp), 0); + mock_resp->errcode = mock_type(int); + + const char * mock_symbol = mock_ptr_type(const char *); + const char * mock_strerr = mock_ptr_type(const char *); + + snprintf((char *)mock_resp->symbol, sizeof(mock_resp->symbol), "%s", mock_symbol); + snprintf((char *)mock_resp->strerr, sizeof(mock_resp->strerr), "%s", mock_strerr); + + /* NOTE: mock_msg_resp must alloc by malloc(), and release by free() */ + struct rte_mp_msg * mock_msg_resp = malloc(sizeof(struct rte_mp_msg)); + memset(mock_msg_resp, 0, sizeof(struct rte_mp_msg)); + + mock_msg_resp->len_param = sizeof(uintptr_t); + *(uintptr_t *)(&mock_msg_resp->param) = (uintptr_t)mock_resp; + + reply->msgs = mock_msg_resp; + } + else + { + assert(0); + } + + if (mock_out_req != NULL) + { + /* copy the param */ + memcpy(mock_out_req->param, req->param, req->len_param); + mock_out_req->len_param = req->len_param; + + /* copy the name */ + snprintf(mock_out_req->name, sizeof(mock_out_req->name), "%s", req->name); + + /* dup the fds */ + for (unsigned int i = 0; i < req->num_fds; i++) + { + mock_out_req->fds[i] = dup(req->fds[i]); + } + + mock_out_req->num_fds = req->num_fds; + } + + return mock_ret; +} + +const char * fake_mrmonit_daemon_text = "{\n" + " \"general\": {\n" + " \"unixtime\": 1718330269,\n" + " \"g_cfgfile\": \"/opt/mrzcpd/etc/mrglobal.conf\",\n" + " \"g_hwfile\": \"/var/run/mrzcpd/hwfile.json\"\n" + " }\n" + "}"; + +static void testcase_marsio_init_register_succ(void ** state) +{ + struct mr_instance * instance = marsio_create(); + assert_non_null(instance); + + unsigned int u32_disable = 0; + marsio_option_set(instance, MARSIO_OPT_EXIT_WHEN_ERR, (void *)&u32_disable, sizeof(u32_disable)); + + /* create a service daemon monit file to simulate the service is running */ + mkdir("/var/run/mrzcpd", 0755); + + FILE * fp = fopen("/var/run/mrzcpd/mrmonit.daemon", "w"); + assert_non_null(fp); + + fprintf(fp, "%s", fake_mrmonit_daemon_text); + fclose(fp); + +#if 0 + will_return(__wrap_rte_eal_init, 0); +#endif + + struct rte_mp_msg msg_req; + will_return(__wrap_rte_mp_request_sync, 0); + will_return(__wrap_rte_mp_request_sync, &msg_req); + will_return(__wrap_rte_mp_request_sync, 0); + will_return(__wrap_rte_mp_request_sync, "test_marsio_init"); + will_return(__wrap_rte_mp_request_sync, "successful"); + + /* should success */ + int ret = marsio_init(instance, "test_marsio_init"); + assert_int_equal(ret, 0); + + /* there's only one fd transfer to service process */ + assert_int_equal(msg_req.num_fds, 1); + + /* try to close the fd to simulate the service exit or crash */ + close(msg_req.fds[0]); + + /* sleep 1s, and the exit should be called */ + sleep(1); + + assert_int_equal(rte_exit_called, 1); + rte_exit_called = 0; + + ret = marsio_destory(instance); + assert_int_equal(ret, 0); +} + +static void testcase_marsio_init_register_failed_by_errcode(void ** state) +{ + struct mr_instance * instance = marsio_create(); + assert_non_null(instance); + + unsigned int u32_disable = 0; + marsio_option_set(instance, MARSIO_OPT_EXIT_WHEN_ERR, (void *)&u32_disable, sizeof(u32_disable)); + + /* create a service daemon monit file to simulate the service is running */ + FILE * fp = fopen("/var/run/mrzcpd/mrmonit.daemon", "w"); + assert_non_null(fp); + + fprintf(fp, "%s", fake_mrmonit_daemon_text); + fclose(fp); + +#if 0 + will_return(__wrap_rte_eal_init, 0); +#endif + + struct rte_mp_msg msg_req; + will_return(__wrap_rte_mp_request_sync, 0); + will_return(__wrap_rte_mp_request_sync, &msg_req); + will_return(__wrap_rte_mp_request_sync, 1); + will_return(__wrap_rte_mp_request_sync, "test_mrapp"); + will_return(__wrap_rte_mp_request_sync, "test_mrapp register failed"); + + /* should fail, as the mrapp register failed */ + int ret = marsio_init(instance, "test_marsio_init"); + assert_int_equal(ret, -1); + + ret = marsio_destory(instance); + assert_int_equal(ret, 0); +} + + +static void testcase_marsio_int_register_failed_by_mp_sync_failed(void ** state) +{ + struct mr_instance * instance = marsio_create(); + assert_non_null(instance); + + unsigned int u32_disable = 0; + marsio_option_set(instance, MARSIO_OPT_EXIT_WHEN_ERR, (void *)&u32_disable, sizeof(u32_disable)); + + /* create a service daemon monit file to simulate the service is running */ + mkdir("/var/run/mrzcpd", 0755); + + /* create a service daemon monit file to simulate the service is running */ + FILE * fp = fopen("/var/run/mrzcpd/mrmonit.daemon", "w"); + assert_non_null(fp); + + fprintf(fp, "%s", fake_mrmonit_daemon_text); + fclose(fp); + + will_return(__wrap_rte_eal_init, 0); + + /* inject the mrapp register failed, ret value and reply value */ + will_return(__wrap_rte_mp_request_sync, -1); + + /* should fail, as the mrapp register failed */ + int ret = marsio_init(instance, "test_marsio_init"); + assert_int_equal(ret, -1); + + ret = marsio_destory(instance); + assert_int_equal(ret, 0); +} + +static void testcase_marsio_init_eal_failed(void ** state) +{ + struct mr_instance * instance = marsio_create(); + assert_non_null(instance); + + unsigned int u32_disable = 0; + marsio_option_set(instance, MARSIO_OPT_EXIT_WHEN_ERR, (void *)&u32_disable, sizeof(u32_disable)); + + /* create a service daemon monit file to simulate the service is running */ + FILE * fp = fopen("/var/run/mrzcpd/mrmonit.daemon", "w"); + assert_non_null(fp); + + fprintf(fp, "%s", fake_mrmonit_daemon_text); + fclose(fp); + + /* inject the eal init failed */ + int inject_eal_init_failed = 1; + will_return(__wrap_rte_eal_init, inject_eal_init_failed); + + /* should fail, as the eal init failed */ + int ret = marsio_init(instance, "test_marsio_init"); + assert_int_equal(ret, -1); + + ret = marsio_destory(instance); + assert_int_equal(ret, 0); +} + +static void testcase_marsio_init_no_service_running(void ** state) +{ + struct mr_instance * instance = marsio_create(); + assert_non_null(instance); + + unsigned int u32_disable = 0; + marsio_option_set(instance, MARSIO_OPT_EXIT_WHEN_ERR, (void *)&u32_disable, sizeof(u32_disable)); + + /* erase the service daemon monit file */ + remove("/var/run/mrzcpd/mrmonit.daemon"); + + /* should fail, as the service is not running */ + int ret = marsio_init(instance, "test_marsio_init"); + assert_int_equal(ret, -1); + + ret = marsio_destory(instance); + assert_int_equal(ret, 0); +} + +static void testcase_marsio_instance_set_thread_mask_in_cpuset(void ** state) +{ + struct mr_instance * instance = marsio_create(); + assert_non_null(instance); + + /* should accept */ + cpu_set_t param_cpu_set = {}; + CPU_SET(1, ¶m_cpu_set); + + int ret = marsio_option_set(instance, MARSIO_OPT_THREAD_MASK_IN_CPUSET, ¶m_cpu_set, sizeof(param_cpu_set)); + assert_int_equal(ret, 0); + + /* size is not enough, input should be rejected */ + unsigned int cpu_set_small = 0; + ret = marsio_option_set(instance, MARSIO_OPT_THREAD_MASK_IN_CPUSET, &cpu_set_small, sizeof(cpu_set_small)); + assert_int_equal(ret, -EINVAL); + +#if 0 + cpu_set_t param_cpu_set_get; + marsio_option_get(instance, MARSIO_OPT_THREAD_MASK_IN_CPUSET, ¶m_cpu_set_get, sizeof(param_cpu_set_get)); + assert_true(CPU_EQUAL(¶m_cpu_set, ¶m_cpu_set_get)); +#endif + + marsio_destory(instance); +} + +static void testcase_marsio_instance_set_thread_num(void ** state) +{ + struct mr_instance * instance = marsio_create(); + assert_non_null(instance); + + /* should accept */ + unsigned int param_thread_num = 4; + int ret = marsio_option_set(instance, MARSIO_OPT_THREAD_NUM, ¶m_thread_num, sizeof(param_thread_num)); + assert_int_equal(ret, 0); + + /* size is not enough, input should be rejected */ + uint8_t param_thread_num_u8 = 8; + ret = marsio_option_set(instance, MARSIO_OPT_THREAD_NUM, ¶m_thread_num_u8, sizeof(param_thread_num_u8)); + assert_int_equal(ret, -EINVAL); + + /* size is larger than expected + * FIXME: the input should be rejected */ + uint64_t param_thread_num_u64 = 8; + ret = marsio_option_set(instance, MARSIO_OPT_THREAD_NUM, ¶m_thread_num_u64, sizeof(param_thread_num_u64)); + assert_int_equal(ret, 0); + +#if 0 + unsigned int param_thread_num_get = 0; + marsio_option_get(instance, MARSIO_OPT_THREAD_NUM, ¶m_thread_num_get, sizeof(param_thread_num)); + assert_int_equal(param_thread_num_get, param_thread_num_u64); +#endif + + marsio_destory(instance); +} + +int main(int argc, char * argv[]) +{ + /* generate the eal args */ + static char * eal_args[] = { + "unittest", + "-c 0x1", + "--no-huge", + "--no-pci", + }; + + /* run the eal with no huge pages */ + int ret = __real_rte_eal_init(RTE_DIM(eal_args), eal_args); + if (ret < 0) + { + rte_exit(EXIT_FAILURE, "Error with EAL initialization\n"); + } + + call_real_rte_mp_request_sync = 0; + const struct CMUnitTest testcases_instance[] = { + cmocka_unit_test(testcase_marsio_instance_set_thread_num), + cmocka_unit_test(testcase_marsio_instance_set_thread_mask_in_cpuset), + cmocka_unit_test(testcase_marsio_init_no_service_running), + cmocka_unit_test(testcase_marsio_init_eal_failed), + cmocka_unit_test(testcase_marsio_int_register_failed_by_mp_sync_failed), + cmocka_unit_test(testcase_marsio_init_register_failed_by_errcode), + cmocka_unit_test(testcase_marsio_init_register_succ), + }; + + cmocka_run_group_tests(testcases_instance, NULL, NULL); + rte_eal_cleanup(); +}
\ No newline at end of file diff --git a/app/test/test_marsio_rawio_api.c b/app/test/test_marsio_rawio_api.c new file mode 100644 index 0000000..1bf0ae3 --- /dev/null +++ b/app/test/test_marsio_rawio_api.c @@ -0,0 +1,509 @@ +#include <stdarg.h> +#include <stddef.h> +#include <stdint.h> +#include <setjmp.h> +#include <string.h> +#include <cmocka.h> +#include <marsio.h> + +#include <rte_mbuf.h> +#include <rte_mempool.h> + +struct rte_mempool * mbuf_pool = NULL; + +int __wrap_vnode_mirror_dequeue_burst(void * cons, unsigned int qid, void * buffs[], unsigned int nr_buffs) +{ + void ** mock_buffs = mock_ptr_type(void **); + unsigned int mock_nr_buffs = mock_type(unsigned int); + unsigned int mock_expect_qid = mock_type(unsigned int); + + if (qid == mock_expect_qid) + { + for (unsigned int i = 0; i < mock_nr_buffs; i++) + { + buffs[i] = mock_buffs[i]; + } + return (int)mock_nr_buffs; + } + else + { + return 0; + } +} + +int __wrap_vnode_mirror_enqueue_bulk(void * prod, unsigned int prodq, struct rte_mbuf * buffs[], + uint32_t hash[], unsigned int nr_buffs) +{ + /* check input parameters */ + check_expected_ptr(buffs); + check_expected(nr_buffs); + + /* fault inject parameter */ + int enq_succ_buff_count = mock_type(int); + assert(nr_buffs >= enq_succ_buff_count); + + /* free the succ enq pkts */ + for (unsigned int i = 0; i < enq_succ_buff_count; i++) + { + rte_pktmbuf_free(buffs[i]); + } + + return 0; +} + +int __wrap_vnode_mirror_rt_object_retrieve(void * prod, unsigned int prodq, struct rte_mbuf * rt_objs[], + unsigned int nr_max_rt_objects) +{ + + void ** mock_buffs = mock_ptr_type(void **); + unsigned int mock_nr_buffs = mock_type(unsigned int); + + for (unsigned int i = 0; i < mock_nr_buffs; i++) + { + rt_objs[i] = mock_buffs[i]; + } + + return (int)mock_nr_buffs; +} + +int __wrap_marsio_buff_free_v2(struct mr_instance * instance, marsio_buff_t * buffs[], unsigned int nr_buffs, + unsigned int flags, unsigned int sid) +{ + for (unsigned int i = 0; i < nr_buffs; i++) + { + rte_pktmbuf_free(buffs[i]); + } + + return 0; +} + +void __wrap_marsio_buff_do_rehash(struct mr_instance * mr_instance, marsio_buff_t * m) +{ + function_called(); +} + +int __wrap_marsio_dp_trace_measurements_can_emit(struct mr_instance * instance, const marsio_buff_t * mbuf, + uint8_t measurement_type) +{ + return 0; +} + +#include <mrapp.h> +struct mr_vdev * __wrap_marsio_open_device(struct mr_instance * instance, const char * devsym, + unsigned int nr_rxstream, + unsigned int nr_txstream) +{ + /* create a fake mr_vdev handle */ + struct mr_vdev * mock_mr_vdev_handle = malloc(sizeof(struct mr_vdev)); + memset(mock_mr_vdev_handle, 0, sizeof(struct mr_vdev)); + + mock_mr_vdev_handle->nr_rxstream = nr_rxstream; + mock_mr_vdev_handle->nr_txstream = nr_txstream; + mock_mr_vdev_handle->instance = instance; + + mock_mr_vdev_handle->vdi = calloc(1, sizeof(struct vdev_instance)); + mock_mr_vdev_handle->tap_representor = NULL; + +#define SZ_VDEV_BUFFER 32 + for (unsigned int i = 0; i < mock_mr_vdev_handle->nr_rxstream; i++) + { + size_t sz_rx_buffer = sizeof(struct mr_vdev_rx_buffer) + sizeof(struct rte_mbuf *) * SZ_VDEV_BUFFER; + mock_mr_vdev_handle->rx_buffer[i] = calloc(1, sz_rx_buffer); + mock_mr_vdev_handle->rx_buffer[i]->size = SZ_VDEV_BUFFER; + } + + for (unsigned int i = 0; i < mock_mr_vdev_handle->nr_txstream; i++) + { + size_t sz_tx_buffer = sizeof(struct mr_vdev_tx_buffer) + sizeof(struct rte_mbuf *) * SZ_VDEV_BUFFER; + mock_mr_vdev_handle->tx_buffer[i] = calloc(1, sz_tx_buffer); + mock_mr_vdev_handle->tx_buffer[i]->size = SZ_VDEV_BUFFER; + } + + assert_non_null(mock_mr_vdev_handle); + return mock_mr_vdev_handle; +} + +void __wrap_marsio_close_device(struct mr_vdev * vdev) +{ + for (unsigned int i = 0; i < vdev->nr_rxstream; i++) + { + free(vdev->rx_buffer[i]); + } + + for (unsigned int i = 0; i < vdev->nr_txstream; i++) + { + free(vdev->tx_buffer[i]); + } + + free(vdev->vdi); + free(vdev); +} + +static void test_recv_burst_api_one_pkt(void ** state) +{ + struct mr_vdev * mock_mr_vdev = marsio_open_device(NULL,"mock_mr_vdev", 2, 1); + assert_non_null(mock_mr_vdev); + + struct rte_mbuf * mbufs_to_recv[1]; + mbufs_to_recv[0] = rte_pktmbuf_alloc(mbuf_pool); + assert_non_null(mbufs_to_recv[0]); + + will_return(__wrap_vnode_mirror_dequeue_burst, mbufs_to_recv); + will_return(__wrap_vnode_mirror_dequeue_burst, 1); + will_return(__wrap_vnode_mirror_dequeue_burst, 0); + + struct rte_mbuf * mbufs_to_recv_ret[1]; + int ret = marsio_recv_burst(mock_mr_vdev, 0, (marsio_buff_t **)mbufs_to_recv_ret, 1); + assert_int_equal(ret, 1); + + /* free the mbuf */ + assert_true(mbufs_to_recv_ret[0] == mbufs_to_recv[0]); + rte_pktmbuf_free(mbufs_to_recv[0]); + + /* make sure no mbuf leak */ + assert_int_equal(rte_mempool_in_use_count(mbuf_pool), 0); + + will_return(__wrap_vnode_mirror_dequeue_burst, NULL); + will_return(__wrap_vnode_mirror_dequeue_burst, 1); + will_return(__wrap_vnode_mirror_dequeue_burst, 0); + + /* try to recv pkt from another queue */ + ret = marsio_recv_burst(mock_mr_vdev, 1, (marsio_buff_t **)mbufs_to_recv_ret, 1); + assert_int_equal(ret, 0); + + /* try to recv pkt from out-of-range queue */ + ret = marsio_recv_burst(mock_mr_vdev, 2, (marsio_buff_t **)mbufs_to_recv_ret, 1); + assert_int_equal(ret, -EINVAL); +} + +static void test_recv_burst_api_many_pkts(void ** state) +{ + struct rte_mbuf * mbufs_to_recv[32] = {}; + for (unsigned int i = 0; i < 32; i++) + { + mbufs_to_recv[i] = rte_pktmbuf_alloc(mbuf_pool); + assert_non_null(mbufs_to_recv[i]); + } + + /* dequeue will get 32 mbufs */ + will_return(__wrap_vnode_mirror_dequeue_burst, mbufs_to_recv); + will_return(__wrap_vnode_mirror_dequeue_burst, 32); + will_return(__wrap_vnode_mirror_dequeue_burst, 0); + + /* call marsio_recv_burst one by one, should get 32 mbufs */ + struct mr_vdev * mock_mr_vdev = marsio_open_device(NULL, "mock_mr_vdev", 1, 1); + for (unsigned int i = 0; i < 32; i++) + { + struct rte_mbuf * mbufs_to_recv_ret[1]; + int ret = marsio_recv_burst(mock_mr_vdev, 0, (marsio_buff_t **)mbufs_to_recv_ret, 1); + assert_int_equal(ret, 1); + + /* free the mbuf */ + assert_true(mbufs_to_recv_ret[0] == mbufs_to_recv[i]); + rte_pktmbuf_free(mbufs_to_recv[i]); + } + + /* make sure no mbuf leak */ + assert_int_equal(rte_mempool_in_use_count(mbuf_pool), 0); +} + +static void test_send_burst_api_one_pkt_succ(void ** state) +{ + struct mr_vdev * mock_mr_vdev = marsio_open_device(NULL, "mock_mr_vdev", 1, 1); + assert_non_null(mock_mr_vdev); + + struct mr_sendpath * mock_sendpath = marsio_sendpath_create_by_vdev(mock_mr_vdev); + assert_non_null(mock_sendpath); + + /* create a mbuf to send */ + struct rte_mbuf * mbufs_to_send[1]; + mbufs_to_send[0] = rte_pktmbuf_alloc(mbuf_pool); + assert_non_null(mbufs_to_send[0]); + + /* no packet drop because of backpressure, all the packets should be sent */ + will_return(__wrap_vnode_mirror_rt_object_retrieve, NULL); + will_return(__wrap_vnode_mirror_rt_object_retrieve, 0); + + /* mbufs_to_send should be call as parameter for vnode_mirror_enqueue_bulk */ + expect_memory(__wrap_vnode_mirror_enqueue_bulk, buffs, mbufs_to_send, 1); + expect_value(__wrap_vnode_mirror_enqueue_bulk, nr_buffs, 1); + will_return(__wrap_vnode_mirror_enqueue_bulk, RTE_DIM(mbufs_to_send)); + + int ret = marsio_send_burst(mock_sendpath, 0, (marsio_buff_t **)mbufs_to_send, 1); + assert_int_equal(ret, 0); + + /* flush */ + struct mr_vdev * vdevs_handles[] = {mock_mr_vdev}; + marsio_poll_wait(mock_mr_vdev->instance, vdevs_handles, RTE_DIM(vdevs_handles), 0, 0); + + /* make sure no mbuf leak */ + assert_true(rte_mempool_full(mbuf_pool)); + marsio_close_device(mock_mr_vdev); +} + +static void test_send_burst_api_one_pkt_drop_by_backpressure(void ** state) +{ + struct mr_vdev * mock_mr_vdev = marsio_open_device(NULL, "mock_mr_vdev", 1, 1); + assert_non_null(mock_mr_vdev); + + struct mr_sendpath * mock_sendpath = marsio_sendpath_create_by_vdev(mock_mr_vdev); + assert_non_null(mock_sendpath); + + /* create a mbuf to send */ + struct rte_mbuf * mbufs_to_send[1]; + mbufs_to_send[0] = rte_pktmbuf_alloc(mbuf_pool); + assert_non_null(mbufs_to_send[0]); + + /* mbufs_to_send should be call as parameter for vnode_mirror_enqueue_bulk */ + expect_memory(__wrap_vnode_mirror_enqueue_bulk, buffs, mbufs_to_send, 1); + expect_value(__wrap_vnode_mirror_enqueue_bulk, nr_buffs, 1); + + /* fault inject, no packet send successfully */ + will_return(__wrap_vnode_mirror_enqueue_bulk, 0); + + /* all packet should be retrieved to simulate the backpressure */ + will_return(__wrap_vnode_mirror_rt_object_retrieve, mbufs_to_send); + will_return(__wrap_vnode_mirror_rt_object_retrieve, 1); + + int ret = marsio_send_burst(mock_sendpath, 0, (marsio_buff_t **)mbufs_to_send, 1); + assert_int_equal(ret, 0); + + /* flush */ + struct mr_vdev * vdevs_handles[] = {mock_mr_vdev}; + marsio_poll_wait(mock_mr_vdev->instance, vdevs_handles, RTE_DIM(vdevs_handles), 0, 0); + + /* make sure no mbuf leak */ + assert_true(rte_mempool_full(mbuf_pool)); + marsio_close_device(mock_mr_vdev); +} + +struct send_with_options_test_state +{ + struct mr_vdev * mock_mr_vdev; + struct mr_sendpath * mock_sendpath; +}; + +/* test group 2: send with options */ +static int testcase_group_SEND_WITH_OPTIONS_setup(void ** state) +{ + struct send_with_options_test_state * test_state = malloc(sizeof(struct send_with_options_test_state)); + memset(test_state, 0, sizeof(struct send_with_options_test_state)); + + test_state->mock_mr_vdev = marsio_open_device(NULL, "mock_mr_vdev", 1, 1); + assert_non_null(test_state->mock_mr_vdev); + + test_state->mock_sendpath = marsio_sendpath_create_by_vdev(test_state->mock_mr_vdev); + assert_non_null(test_state->mock_sendpath); + + *state = test_state; + return 0; +} + +static int testcase_group_SEND_WITH_OPTIONS_teardown(void ** state) +{ + struct send_with_options_test_state * test_state = *state; + if (test_state != NULL) + { + marsio_close_device(test_state->mock_mr_vdev); + marsio_sendpath_destory(test_state->mock_sendpath); + free(test_state); + } + + return 0; +} + +static void test_send_with_options_do_not_free(void ** state) +{ + struct send_with_options_test_state * test_state = *state; + assert_non_null(test_state); + + struct rte_mbuf * mbufs_to_send[1]; + mbufs_to_send[0] = rte_pktmbuf_alloc(mbuf_pool); + assert_non_null(mbufs_to_send[0]); + + /* mbufs_to_send should be call as parameter for vnode_mirror_enqueue_bulk */ + expect_memory(__wrap_vnode_mirror_enqueue_bulk, buffs, mbufs_to_send, 1); + expect_value(__wrap_vnode_mirror_enqueue_bulk, nr_buffs, 1); + + /* packet should be sent successfully, no packet drop */ + will_return(__wrap_vnode_mirror_enqueue_bulk, 1); + will_return(__wrap_vnode_mirror_rt_object_retrieve, NULL); + will_return(__wrap_vnode_mirror_rt_object_retrieve, 0); + + /* call send with option, do not free the packet */ + int ret = marsio_send_burst_with_options(test_state->mock_sendpath, 0, (marsio_buff_t **)mbufs_to_send, 1, + MARSIO_SEND_OPT_NO_FREE); + + /* always success */ + assert_int_equal(ret, 0); + + /* since the pkt has been set to no free */ + assert_int_equal(rte_mempool_in_use_count(mbuf_pool), 1); + + /* free the mbuf */ + rte_pktmbuf_free(mbufs_to_send[0]); + assert_true(rte_mempool_full(mbuf_pool)); +} + +static void test_send_with_options_rehash(void ** state) +{ + struct send_with_options_test_state * test_state = *state; + assert_non_null(test_state); + + struct rte_mbuf * mbufs_to_send[1]; + mbufs_to_send[0] = rte_pktmbuf_alloc(mbuf_pool); + + /* mbufs_to_send should be call as parameter for vnode_mirror_enqueue_bulk */ + expect_memory(__wrap_vnode_mirror_enqueue_bulk, buffs, mbufs_to_send, 1); + expect_value(__wrap_vnode_mirror_enqueue_bulk, nr_buffs, 1); + + /* packet should be sent successfully, no packet drop */ + will_return(__wrap_vnode_mirror_enqueue_bulk, 1); + will_return(__wrap_vnode_mirror_rt_object_retrieve, NULL); + will_return(__wrap_vnode_mirror_rt_object_retrieve, 0); + + /* marsio_do_rehash should be called */ + expect_function_call(__wrap_marsio_buff_do_rehash); + + /* call send with option, do rehash */ + int ret = marsio_send_burst_with_options(test_state->mock_sendpath, 0, (marsio_buff_t **)mbufs_to_send, 1, + MARSIO_SEND_OPT_REHASH); + + /* always success */ + assert_int_equal(ret, 0); + + /* check the mbuf leak */ + assert_true(rte_mempool_full(mbuf_pool)); +} + +static void test_send_with_options_many_pkts(void ** state) +{ + struct send_with_options_test_state * test_state = *state; + assert_non_null(test_state); + + struct rte_mbuf * mbufs_to_send[32] = {}; + for (unsigned int i = 0; i < 32; i++) + { + mbufs_to_send[i] = rte_pktmbuf_alloc(mbuf_pool); + assert_non_null(mbufs_to_send[i]); + } + + /* mbufs_to_send should be call as parameter for vnode_mirror_enqueue_bulk */ + expect_memory(__wrap_vnode_mirror_enqueue_bulk, buffs, mbufs_to_send, 32); + expect_value(__wrap_vnode_mirror_enqueue_bulk, nr_buffs, 32); + + /* fault inject, all packet send successfully */ + will_return(__wrap_vnode_mirror_enqueue_bulk, 32); + will_return(__wrap_vnode_mirror_rt_object_retrieve, NULL); + will_return(__wrap_vnode_mirror_rt_object_retrieve, 0); + + /* call send with option, no options */ + int ret = marsio_send_burst_with_options(test_state->mock_sendpath, 0, (marsio_buff_t **)mbufs_to_send, 32, 0); + assert_int_equal(ret, 0); + + /* make sure no mbuf leak */ + assert_int_equal(rte_mempool_in_use_count(mbuf_pool), 0); +} + +#if 0 +static void test_mix_send_with_option_and_send_burst(void ** state) +{ + struct send_with_options_test_state * test_state = *state; + assert_non_null(test_state); + + struct rte_mbuf * mbufs_to_send[32] = {}; + for (unsigned int i = 0; i < 32; i++) + { + mbufs_to_send[i] = rte_pktmbuf_alloc(mbuf_pool); + assert_non_null(mbufs_to_send[i]); + } + + /* mbufs_to_send should be call as parameter for vnode_mirror_enqueue_bulk */ + expect_memory(__wrap_vnode_mirror_enqueue_bulk, buffs, mbufs_to_send, 32); + expect_value(__wrap_vnode_mirror_enqueue_bulk, nr_buffs, 32); + + /* fault inject, all packet send successfully */ + will_return(__wrap_vnode_mirror_enqueue_bulk, 32); + will_return(__wrap_vnode_mirror_rt_object_retrieve, NULL); + will_return(__wrap_vnode_mirror_rt_object_retrieve, 0); + + /* call send with option, no options */ + int ret = marsio_send_burst_with_options(test_state->mock_sendpath, 0, (marsio_buff_t **)mbufs_to_send, 32, 0); + assert_int_equal(ret, 0); + + /* make sure no mbuf leak */ + assert_int_equal(rte_mempool_in_use_count(mbuf_pool), 0); + + /* free the mbuf */ + for (unsigned int i = 0; i < 32; i++) + { + mbufs_to_send[i] = rte_pktmbuf_alloc(mbuf_pool); + assert_non_null(mbufs_to_send[i]); + } + + /* mbufs_to_send should be call as parameter for vnode_mirror_enqueue_bulk */ + expect_memory(__wrap_vnode_mirror_enqueue_bulk, buffs, mbufs_to_send, 32); + expect_value(__wrap_vnode_mirror_enqueue_bulk, nr_buffs, 32); + + /* fault inject, all packet send successfully */ + will_return(__wrap_vnode_mirror_enqueue_bulk, 32); + will_return(__wrap_vnode_mirror_rt_object_retrieve, NULL); + will_return(__wrap_vnode_mirror_rt_object_retrieve, 0); + + /* first 16 mbufs, send by send burst */ + ret = marsio_send_burst(test_state->mock_sendpath, 0, (marsio_buff_t **)mbufs_to_send, 16); + assert_int_equal(ret, 0); + + /* second 16 mbufs, send by send burst with options */ + ret = marsio_send_burst_with_options(test_state->mock_sendpath, 0, (marsio_buff_t **)mbufs_to_send + 16, 16, 0); + assert_int_equal(ret, 0); + + /* poll and wait */ + struct mr_vdev * vdevs_handles[] = {test_state->mock_mr_vdev}; + marsio_poll_wait(test_state->mock_mr_vdev->instance, vdevs_handles, RTE_DIM(vdevs_handles), 0, 0); + + /* make sure no mbuf leak */ + assert_int_equal(rte_mempool_in_use_count(mbuf_pool), 0); +} +#endif + +int main(int argc, char * argv[]) +{ + /* generate the eal args */ + static char * eal_args[] = { + "test_marsio_rawio_api", + "-c 0x1", + "--no-huge", + "--no-pci", + }; + + /* run the eal with no huge pages */ + int ret = rte_eal_init(RTE_DIM(eal_args), eal_args); + if (ret < 0) + { + rte_exit(EXIT_FAILURE, "Error with EAL initialization\n"); + } + + /* init the mbuf pool */ + mbuf_pool = rte_pktmbuf_pool_create("MBUF_POOL", 8192, 32, 0, RTE_MBUF_DEFAULT_BUF_SIZE, SOCKET_ID_ANY); + + const struct CMUnitTest tests[] = { + cmocka_unit_test(test_recv_burst_api_one_pkt), + cmocka_unit_test(test_recv_burst_api_many_pkts), + cmocka_unit_test(test_send_burst_api_one_pkt_succ), + cmocka_unit_test(test_send_burst_api_one_pkt_drop_by_backpressure), + }; + + const struct CMUnitTest testcase_send_with_options[] = { + cmocka_unit_test_setup_teardown(test_send_with_options_do_not_free, NULL, NULL), + cmocka_unit_test_setup_teardown(test_send_with_options_rehash, NULL, NULL), + cmocka_unit_test_setup_teardown(test_send_with_options_many_pkts, NULL, NULL), +#if 0 + cmocka_unit_test_setup_teardown(test_mix_send_with_option_and_send_burst, NULL, NULL), +#endif + }; + + cmocka_run_group_tests(tests, NULL, NULL); + cmocka_run_group_tests(testcase_send_with_options, testcase_group_SEND_WITH_OPTIONS_setup, + testcase_group_SEND_WITH_OPTIONS_teardown); +}
\ No newline at end of file diff --git a/infra/CMakeLists.txt b/infra/CMakeLists.txt index d03ee25..79a3368 100644 --- a/infra/CMakeLists.txt +++ b/infra/CMakeLists.txt @@ -44,3 +44,12 @@ target_include_directories(TestPortAdapterMapping PRIVATE include) add_executable(TestDataPathTrace test/TestDataPathTrace.cc) target_link_libraries(TestDataPathTrace gtest_main infra z elf ibverbs mlx5 libdpdk ${SYSTEMD_LIBRARIES}) target_include_directories(TestDataPathTrace PRIVATE include) + +add_test(TestPacketParser TestPacketParser) +add_test(TestDistributer TestDistributer) +add_test(TestVNode TestVNode) +add_test(TestPktClassifierEngine TestPktClassifierEngine) +add_test(TestSidList TestSidList) +add_test(TestLinkDb TestLinkDb) +add_test(TestPortAdapterMapping TestPortAdapterMapping) +add_test(TestDataPathTrace TestDataPathTrace)
\ No newline at end of file diff --git a/infra/src/port_adapter_mapping.c b/infra/src/port_adapter_mapping.c index adc7171..f8e5da9 100644 --- a/infra/src/port_adapter_mapping.c +++ b/infra/src/port_adapter_mapping.c @@ -15,7 +15,7 @@ static struct port_adapter_mapping_mgr * g_mapping_mgr = NULL; /* port adapter mapping init */ int port_adapter_mapping_init(void) { - assert(g_mapping_mgr == NULL); + MR_VERIFY(g_mapping_mgr == NULL); g_mapping_mgr = ZMALLOC(sizeof(struct port_adapter_mapping_mgr)); for (int i = 0; i < RTE_DIM(g_mapping_mgr->port_adapter_maps); i++) @@ -38,9 +38,9 @@ int port_adapter_mapping_deinit(void) /* port adapter mapping insert,not thread-safe */ int port_adapter_mapping_insert(port_id_t port_id, enum adapter_type adapter_type) { - assert(g_mapping_mgr != NULL); - assert(g_mapping_mgr->nr_maps < RTE_DIM(g_mapping_mgr->port_adapter_maps)); - assert(port_id < RTE_DIM(g_mapping_mgr->port_adapter_maps)); + MR_VERIFY(g_mapping_mgr != NULL); + MR_VERIFY(g_mapping_mgr->nr_maps < RTE_DIM(g_mapping_mgr->port_adapter_maps)); + MR_VERIFY(port_id < RTE_DIM(g_mapping_mgr->port_adapter_maps)); if (g_mapping_mgr->port_adapter_maps[port_id] != ADAPTER_TYPE_NONE) { diff --git a/infra/test/TestDataPathTrace.cc b/infra/test/TestDataPathTrace.cc index 721f1f2..105b444 100644 --- a/infra/test/TestDataPathTrace.cc +++ b/infra/test/TestDataPathTrace.cc @@ -73,11 +73,10 @@ class DataPathTraceTest : public testing::Test protected: static void SetUpTestCase() { - int argc = 1; - const char * argv[] = {"TestDataPathTrace", "-c 0x1"}; - if (rte_eal_init(argc, const_cast<char **>(argv)) < 0) + const char * argv[] = {"TestDataPathTrace", "-c", "0x1", "--no-huge", "-m", "512"}; + if (rte_eal_init(RTE_DIM(argv), (char **)argv) < 0) { - rte_exit(EXIT_FAILURE, "fail in init"); + rte_exit(EXIT_FAILURE, "failed at rte_eal_init()"); } } @@ -157,7 +156,7 @@ class DataPathTraceTest : public testing::Test struct rte_mempool * mempool; }; -TEST_F(DataPathTraceTest, PackageConstruct) +TEST_F(DataPathTraceTest, PacketConstruct) { struct rte_mbuf * pkt73_mbuf = mbuf_construct(pkt73, sizeof(pkt73)); struct mrb_metadata * mrb_meta = (struct mrb_metadata *)mrbuf_cz_data(pkt73_mbuf, 1); diff --git a/infra/test/TestLinkDb.cc b/infra/test/TestLinkDb.cc index e88fdc0..a050da1 100644 --- a/infra/test/TestLinkDb.cc +++ b/infra/test/TestLinkDb.cc @@ -384,6 +384,7 @@ TEST(TestCaseLinkDb, RulesNumberOutOfMaxEntries) } /* Type is invalid */ +#if 0 TEST(TestCaseLinkDb, TypeInvalid) { ASSERT_DEATH(link_db_create(LINK_DB_TYPE_MAX, 32), "./*"); @@ -412,6 +413,7 @@ TEST(TestCaseLinkDb, ExceedMaxNumOfMatches) uint16_t result[17]; ASSERT_DEATH(link_db_match(ctx, match_field, 17, result);, "./*"); } +#endif /* Main func */ int main(int argc, char * argv[]) diff --git a/service/CMakeLists.txt b/service/CMakeLists.txt index 22dcb4c..1db8a7c 100644 --- a/service/CMakeLists.txt +++ b/service/CMakeLists.txt @@ -1,23 +1,39 @@ find_package(SYSTEMD REQUIRED) - include_directories(include) -add_executable(mrzcpd src/core.c src/devmgr.c src/mrb.c src/hwinfo.c src/vdev.c - src/vdata.c src/app.c src/monit.c src/node.c src/node_shmdev.c - src/node_phydev.c src/node_lb.c src/node_classifier.c src/node_etherfabric.c src/node_tera.c - src/node_eth_ingress.c src/node_eth_egress.c src/node_bfd.c src/node_vwire.c - src/node_health_check.c src/node_forwarder.c src/node_bridge.c src/pdump.c src/olp.c src/olp_6500.c - src/http_serv.c src/classifier_rule_parser.c src/mpack.c src/dp_trace.c src/node_link_aware_injector.c) +set(MRZCPD_SERVICE_SOURCE_FILES src/core.c src/devmgr.c src/mrb.c src/hwinfo.c src/vdev.c + src/vdata.c src/app.c src/monit.c src/node.c src/node_shmdev.c + src/node_phydev.c src/node_lb.c src/node_classifier.c src/node_etherfabric.c src/node_tera.c + src/node_eth_ingress.c src/node_eth_egress.c src/node_bfd.c src/node_vwire.c + src/node_health_check.c src/node_forwarder.c src/node_bridge.c src/pdump.c src/olp.c src/olp_6500.c + src/http_serv.c src/classifier_rule_parser.c src/mpack.c src/dp_trace.c src/node_link_aware_injector.c) +add_executable(mrzcpd src/main.c ${MRZCPD_SERVICE_SOURCE_FILES}) target_link_libraries(mrzcpd MESA_prof_load_static libdpdk ${SYSTEMD_LIBRARIES}) target_link_libraries(mrzcpd rt pthread dl infra z elf) target_include_directories(mrzcpd INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}/include/") target_include_directories(mrzcpd INTERFACE ${SYSTEMD_INCLUDE_DIRS}) - install(TARGETS mrzcpd RUNTIME DESTINATION ${MR_INSTALL_BINDIR} COMPONENT Program) -add_executable(TestOLP test/TestOLP.cc src/olp_6500.c) -target_link_libraries(TestOLP gtest_main MESA_prof_load_static ${SYSTEMD_LIBRARIES} libdpdk) -target_link_libraries(TestOLP rt pthread dl infra z elf) -target_include_directories(TestOLP PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/include/") -target_include_directories(TestOLP PRIVATE ${SYSTEMD_INCLUDE_DIRS}) + +########################################### UNITTESTS ########################################### +#add_executable(TestOLP test/TestOLP.cc src/olp_6500.c) +#target_link_libraries(TestOLP gtest_main MESA_prof_load_static ${SYSTEMD_LIBRARIES} libdpdk) +#target_link_libraries(TestOLP rt pthread dl infra z elf) +#target_include_directories(TestOLP PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/include/") +#target_include_directories(TestOLP PRIVATE ${SYSTEMD_INCLUDE_DIRS}) + +add_executable(test_node_vwire test/test_node_mocks.c test/test_node_vwire.c ${MRZCPD_SERVICE_SOURCE_FILES}) +target_compile_options(test_node_vwire PRIVATE --coverage -fprofile-arcs -ftest-coverage) +target_link_libraries(test_node_vwire MESA_prof_load_static ${SYSTEMD_LIBRARIES} libdpdk) +target_link_libraries(test_node_vwire libcmocka rt pthread dl infra z elf) +target_link_options(test_node_vwire PRIVATE --coverage -fprofile-arcs -ftest-coverage) +target_include_directories(test_node_vwire PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/include/") +target_link_libraries(test_node_vwire -Wl,--wrap=mr_dev_desc_lookup) +target_link_libraries(test_node_vwire -Wl,--wrap=forwarder_table_insert) +target_link_libraries(test_node_vwire -Wl,--wrap=classifier_node_process) +target_link_libraries(test_node_vwire -Wl,--wrap=pkt_drop_trap_process) +target_link_libraries(test_node_vwire -Wl,--wrap=rte_eal_init) +target_link_libraries(test_node_vwire -Wl,--wrap=rte_exit) + +add_test(NAME test_node_vwire COMMAND test_node_vwire)
\ No newline at end of file diff --git a/service/include/sc_node_common.h b/service/include/sc_node_common.h index 1f8dc7f..7e672d1 100644 --- a/service/include/sc_node_common.h +++ b/service/include/sc_node_common.h @@ -62,7 +62,7 @@ struct mr_generic_ip_hdr }; }; -void forwarder_table_inserter(uint16_t sid, uint16_t type); +void forwarder_table_insert(uint16_t sid, uint16_t type); static inline void swap_mac_addr(struct rte_ether_hdr * eth_hdr) { diff --git a/service/src/core.c b/service/src/core.c index df04aa1..3a209b6 100644 --- a/service/src/core.c +++ b/service/src/core.c @@ -732,61 +732,6 @@ void __setproctitle_init(int argc, char ** argv, char ** envp) return; } -static void __setproctitle(const char * fmt, ...) -{ - char * p; - int i; - char buf[LINE_MAX] = {0}; - - extern char ** __main_argv; - extern char * __main_last_argv; - va_list ap; - p = buf; - - va_start(ap, fmt); - vsprintf(p, fmt, ap); - va_end(ap); - - i = strlen(buf); - - if (i > __main_last_argv - __main_argv[0] - 2) - { - i = __main_last_argv - __main_argv[0] - 2; - buf[i] = '\0'; - } - - // 修改argv[0] - (void)strcpy(__main_argv[0], buf); - - p = &__main_argv[0][i]; - while (p < __main_last_argv) - *p++ = '\0'; - - __main_argv[1] = NULL; - - // 调用prctl - prctl(PR_SET_NAME, buf); - return; -} - -static int sc_proc_symbol_setup(struct sc_main * sc, int argc, char * argv[]) -{ - char str_prog_symbol[MR_SYMBOL_MAX] = {0}; - - /* 兼容MARSIO3.0,自定义服务进程名称。 - T1/T2系统已经使用了MARSIO进程名,避免更改进程名引起监控脚本失效。 - */ - int ret = MESA_load_profile_string_nodef(sc->local_cfgfile, "compat", "progsym", str_prog_symbol, - sizeof(str_prog_symbol)); - - if (ret < 0) - return RT_SUCCESS; - - __setproctitle_init(argc, argv, environ); - __setproctitle("%s", str_prog_symbol); - return RT_SUCCESS; -} - struct service_performance_monit { unsigned int service_id; @@ -986,7 +931,7 @@ extern int http_serv_init(struct sc_main * sc_main); extern int olp_manager_init(struct sc_main * sc_main); extern int lai_init(struct sc_main * sc); -int main(int argc, char * argv[]) +int marsio_service_main(int argc, char * argv[]) { /* 解析命令行参数 */ struct sc_main * sc = sc_main_new(); @@ -1005,9 +950,13 @@ int main(int argc, char * argv[]) /* 通过Systemd启动,关闭标准输出,采用syslog方式记录日志 */ if (__check_is_notify()) + { g_logger_to_stdout = 0; + } else + { g_logger_to_stdout = 1; + } int ret = 0; int opt = 0; @@ -1042,17 +991,12 @@ int main(int argc, char * argv[]) unsigned int pdump_inited = 0; if (g_logger_to_stdout) + { MR_INFO("%s", mr_logo); + } MR_INFO("MARSIO ZeroCopy Packet I/O Driver, Version: %s, build with %s", service_git_version, rte_version()); - /* Compatible with MARSIO3, change the process name */ - if (sc_proc_symbol_setup(sc, argc, argv) != RT_SUCCESS) - { - MR_ERROR("Process symbol setup failed. "); - goto quit; - } - /* Check Configure File */ if (access(sc->local_cfgfile, R_OK) != 0) { diff --git a/service/src/main.c b/service/src/main.c new file mode 100644 index 0000000..1588d89 --- /dev/null +++ b/service/src/main.c @@ -0,0 +1,9 @@ +// +// Created by luqiu on 2024/6/18. +// + +extern int marsio_service_main(int argc, char * argv[]); +int main(int argc, char *argv[]) +{ + return marsio_service_main(argc, argv); +}
\ No newline at end of file diff --git a/service/src/node_bfd.c b/service/src/node_bfd.c index baf13b2..5a8e812 100644 --- a/service/src/node_bfd.c +++ b/service/src/node_bfd.c @@ -100,6 +100,8 @@ uint16_t get_bfd_session_id(rte_graph_t graph_id, struct rte_ipv4_hdr * ipv4_hdr return get_free_session_id(graph_id, ipv4_hdr); } +#define BFD_USE_YOUR_DISCRIMINATOR_AS_MY_DISCRIMINATOR 0 + /* Reply Bfd Request */ uint8_t bfd_reply(struct rte_ether_hdr * ether_hdr, struct rte_ipv4_hdr * ipv4_hdr, struct rte_udp_hdr * udp_hdr, uint16_t bfd_session_id) @@ -123,10 +125,17 @@ uint8_t bfd_reply(struct rte_ether_hdr * ether_hdr, struct rte_ipv4_hdr * ipv4_h /* Swap discriminator */ struct bfd_header_t * bfd_hdr = (struct bfd_header_t *)(udp_hdr + 1); uint8_t swap_discriminator[4]; + +#if BFD_USE_YOUR_DISCRIMINATOR_AS_MY_DISCRIMINATOR + memcpy(swap_discriminator, bfd_hdr->your_discriminator, sizeof(swap_discriminator)); + memcpy(bfd_hdr->your_discriminator, bfd_hdr->my_discriminator, sizeof(swap_discriminator)); + memcpy(bfd_hdr->my_discriminator, swap_discriminator, sizeof(swap_discriminator)); +#else uint32_t discriminator = htonl(MR_BFD_START_DISCRIMINATOR + bfd_session_id); memcpy(swap_discriminator, bfd_hdr->my_discriminator, sizeof(swap_discriminator)); memcpy(bfd_hdr->my_discriminator, &discriminator, sizeof(swap_discriminator)); memcpy(bfd_hdr->your_discriminator, swap_discriminator, sizeof(swap_discriminator)); +#endif /* Set udp check sum */ udp_hdr->dgram_cksum = 0; diff --git a/service/src/node_etherfabric.c b/service/src/node_etherfabric.c index b49d631..c81080a 100644 --- a/service/src/node_etherfabric.c +++ b/service/src/node_etherfabric.c @@ -344,7 +344,7 @@ int parser_ef_adapter_config(struct sc_main * sc, struct node_ef_main * ef_main) if (ef_adapter->mode == MODE_INVALID) continue; - forwarder_table_inserter(sid_start + ef_adapter->ef_adapter_id, FORWARDER_TYPE_EF); + forwarder_table_insert(sid_start + ef_adapter->ef_adapter_id, FORWARDER_TYPE_EF); } /* Save the etherfabric adapter config num */ diff --git a/service/src/node_forwarder.c b/service/src/node_forwarder.c index 3245b24..36dedef 100644 --- a/service/src/node_forwarder.c +++ b/service/src/node_forwarder.c @@ -75,7 +75,7 @@ int sid_check(uint32_t sid) } /* Forwarder table inserter */ -void forwarder_table_inserter(uint16_t sid, uint16_t type) +void forwarder_table_insert(uint16_t sid, uint16_t type) { char str_forwarder[1024] = {}; struct forwarder_main * forwarder_main = forwarder_main_get(); diff --git a/service/src/node_lb.c b/service/src/node_lb.c index f86fcbe..cb4b0cb 100644 --- a/service/src/node_lb.c +++ b/service/src/node_lb.c @@ -356,7 +356,7 @@ int parser_local_lb_conf(struct sc_main * sc, struct node_lb_main * lb_main) { struct lb_group * lb_group = &lb_main->lb_groups[i]; if (lb_group->group_status == GROUP_STATUS_IN_USE) - forwarder_table_inserter(lb_group->sid, FORWARDER_TYPE_LB); + forwarder_table_insert(lb_group->sid, FORWARDER_TYPE_LB); } /* Save sid info */ diff --git a/service/src/node_link_aware_injector.c b/service/src/node_link_aware_injector.c index d98ceac..e9c5a55 100644 --- a/service/src/node_link_aware_injector.c +++ b/service/src/node_link_aware_injector.c @@ -115,7 +115,7 @@ int lai_init(struct sc_main * sc) } /* Inserter sid to forwarder table */ - forwarder_table_inserter(lai_main->lai_sid, FORWARDER_TYPE_LAI); + forwarder_table_insert(lai_main->lai_sid, FORWARDER_TYPE_LAI); /* Get ef adapter ids */ lai_main->nr_ef_adapters = ef_nr_adapters_get(); diff --git a/service/src/node_tera.c b/service/src/node_tera.c index a28c90d..93a9ae3 100644 --- a/service/src/node_tera.c +++ b/service/src/node_tera.c @@ -214,7 +214,7 @@ int tera_config_parse(struct sc_main * sc, struct node_tera_main * tera_main) if (adapter->listen_device == NULL) continue; - forwarder_table_inserter(sid_start + adapter->tera_adapter_id, FORWARDER_TYPE_TERA); + forwarder_table_insert(sid_start + adapter->tera_adapter_id, FORWARDER_TYPE_TERA); } /* Save the sid and nr adapters */ diff --git a/service/src/node_vwire.c b/service/src/node_vwire.c index 1b57073..d0d6a96 100644 --- a/service/src/node_vwire.c +++ b/service/src/node_vwire.c @@ -206,7 +206,6 @@ static __rte_always_inline uint16_t vwire_ingress_node_process(struct rte_graph stats.drop_pkts++; } -#if 0 /* Check if tracing is enabled for the current Mbuf */ if (unlikely(dp_trace_record_can_emit(mbuf0, DP_TRACE_MEASUREMENT_TYPE_TRACE))) { @@ -218,7 +217,6 @@ static __rte_always_inline uint16_t vwire_ingress_node_process(struct rte_graph { gen_store_telemetry_info_adapter(mbuf0); } -#endif if (unlikely(next_index ^ next0)) { @@ -519,11 +517,12 @@ errout: int vwire_init(struct sc_main * sc) { - /* Get ef max entry,default is 256 */ - MESA_load_profile_uint_def(sc->local_cfgfile, "limits", "nr_max_vwires", &nr_max_vwires, 256); struct vwire_node_main * vwire_node_main = ZMALLOC(sizeof(struct vwire_node_main)); MR_VERIFY_MALLOC(vwire_node_main); + /* Get ef max entry,default is 256 */ + MESA_load_profile_uint_def(sc->local_cfgfile, "limits", "nr_max_vwires", &nr_max_vwires, 256); + vwire_node_main->forward_rules = ZMALLOC(sizeof(struct vwire_forward_rule *) * nr_max_vwires); MR_VERIFY_MALLOC(vwire_node_main->forward_rules); @@ -584,7 +583,11 @@ int vwire_init(struct sc_main * sc) return RT_ERR; } - vwire_forward_rule_add__DEV_TYPE(p_vwire_node_main, sc, str_int_dev, str_ext_dev, vwire_id); + ret = vwire_forward_rule_add__DEV_TYPE(p_vwire_node_main, sc, str_int_dev, str_ext_dev, vwire_id); + if (ret < 0) + { + return RT_ERR; + } char str_obp_dev[MR_SYMBOL_MAX] = {}; ret = MESA_load_profile_string_nodef(sc->local_cfgfile, sec_symbol, "obp_device", str_obp_dev, @@ -616,7 +619,7 @@ int vwire_init(struct sc_main * sc) continue; uint16_t sid = sid_start + fwd_rule->vwire_id; - forwarder_table_inserter(sid, FORWARDER_TYPE_VWIRE); + forwarder_table_insert(sid, FORWARDER_TYPE_VWIRE); } /* Save sid info */ @@ -628,11 +631,17 @@ int vwire_init(struct sc_main * sc) uint32_t max_entries; MESA_load_profile_uint_def(sc->local_cfgfile, "limits", "nr_max_link_dbs", &max_entries, 64); p_vwire_node_main->link_db_ctx = link_db_create(LINK_DB_TYPE_VWIRE, max_entries); + if (p_vwire_node_main->link_db_ctx == NULL) + { return RT_ERR; + } - if (link_db_config_parse(sc->local_cfgfile, p_vwire_node_main->link_db_ctx) == RT_ERR) + ret = link_db_config_parse(sc->local_cfgfile, p_vwire_node_main->link_db_ctx); + if (ret < 0) + { return RT_ERR; + } return 0; } diff --git a/service/test/test_node_mocks.c b/service/test/test_node_mocks.c new file mode 100644 index 0000000..564cd64 --- /dev/null +++ b/service/test/test_node_mocks.c @@ -0,0 +1,70 @@ +#include <stdint.h> +#include <rte_graph.h> +#include <rte_graph_worker.h> +#include <stdarg.h> +#include <stddef.h> +#include <stdint.h> +#include <setjmp.h> +#include <cmocka.h> + +uint16_t mock_pkt_input_process(struct rte_graph * graph, struct rte_node * node, void ** objs, uint16_t cnt) +{ + unsigned int nr_source_pkts = mock_type(unsigned int); + struct rte_mbuf ** source_mbufs = mock_ptr_type(struct rte_mbuf **); + + rte_node_enqueue(graph, node, 0, (void **)source_mbufs, nr_source_pkts); + return nr_source_pkts; +} + +uint16_t mock_pkt_output_process(struct rte_graph * graph, struct rte_node * node, void ** objs, uint16_t cnt) +{ + struct rte_mbuf ** output_mbufs = mock_ptr_type(struct rte_mbuf **); + unsigned int * nr_output_pkts = mock_ptr_type(unsigned int *); + + for (int i = 0; i < cnt; i++) + { + output_mbufs[i] = objs[i]; + } + + *nr_output_pkts = (unsigned int)cnt; + return cnt; +} + +uint16_t mock_pkt_drop_process(struct rte_graph * graph, struct rte_node * node, void ** objs, uint16_t cnt) +{ + struct rte_mbuf ** output_mbufs = mock_ptr_type(struct rte_mbuf **); + unsigned int * nr_output_pkts = mock_ptr_type(unsigned int *); + + for (int i = 0; i < cnt; i++) + { + output_mbufs[i] = objs[i]; + } + + *nr_output_pkts = (unsigned int)cnt; + return cnt; +} + +struct rte_node_register mock_pkt_output_node = { + .process = mock_pkt_output_process, + .name = "mock_pkt_output", +}; + +struct rte_node_register mock_pkt_drop_node = { + .process = mock_pkt_drop_process, + .name = "mock_pkt_drop", +}; + +struct rte_node_register mock_pkt_input_node = { + .process = mock_pkt_input_process, + .name = "mock_pkt_input", + .nb_edges = 1, + .next_nodes = + { + "vwire_ingress", + }, + .flags = RTE_NODE_SOURCE_F, +}; + +RTE_NODE_REGISTER(mock_pkt_input_node); +RTE_NODE_REGISTER(mock_pkt_output_node); +RTE_NODE_REGISTER(mock_pkt_drop_node);
\ No newline at end of file diff --git a/service/test/test_node_vwire.c b/service/test/test_node_vwire.c new file mode 100644 index 0000000..260badc --- /dev/null +++ b/service/test/test_node_vwire.c @@ -0,0 +1,414 @@ +#include <stdarg.h> +#include <stddef.h> +#include <stdint.h> +#include <setjmp.h> +#include <string.h> +#include <cmocka.h> +#include <rte_eal.h> +#include <rte_mempool.h> +#include <rte_graph.h> +#include <rte_graph_worker.h> + +#include <sc_node.h> +#include <sc_node_common.h> + +static struct rte_mempool * mock_pktmbuf_pool = NULL; + +int __wrap_rte_eal_init(int argc, char * argv[]) +{ + int inject_eal_init_failed = mock_type(int); + if (inject_eal_init_failed) + { + return -1; + } + + return 0; +} + +static int rte_exit_called = 0; +int __wrap_rte_exit(int status, const char *format, ...) +{ + rte_exit_called = 1; + return 0; +} + +struct mr_dev_desc * __wrap_mr_dev_desc_lookup(struct devmgr_main * devmgr_main, const char * devsym) +{ + check_expected(devsym); + return mock_type(struct mr_dev_desc *); +} + +void __wrap_forwarder_table_insert(uint16_t sid, uint16_t type) +{ + check_expected(sid); + check_expected(type); +} + +extern int __real_rte_eal_init(int argc, char **argv); +extern int __real_rte_exit(int status, const char *format, ...); + +extern int vwire_init(struct sc_main * sc); + + +/* testcase: 1 + * device: vwire_1 <-> vwire_2 + * port_id: 1 <-> 2 +*/ + +static void testcase_vwire_ingress_forward_pkts(void ** state) +{ + struct rte_graph * graph_ptr = rte_graph_lookup("test_vwire_ingress"); + assert_non_null(graph_ptr); + + /* alloc the mbuf as input */ + struct rte_mbuf * mbuf_input[3]; + mbuf_input[0] = rte_pktmbuf_alloc(mock_pktmbuf_pool); + mbuf_input[1] = rte_pktmbuf_alloc(mock_pktmbuf_pool); + mbuf_input[2] = rte_pktmbuf_alloc(mock_pktmbuf_pool); + + assert_non_null(mbuf_input[0]); + assert_non_null(mbuf_input[1]); + assert_non_null(mbuf_input[2]); + + /* set the mbuf data */ + will_return(mock_pkt_input_process, 3); + will_return(mock_pkt_input_process, mbuf_input); + + struct rte_mbuf * mbuf_output[2] = {}; + unsigned int nr_mbuf_output = 0; + + will_return(mock_pkt_output_process, mbuf_output); + will_return(mock_pkt_output_process, &nr_mbuf_output); + + struct rte_mbuf * mbuf_drop[1] = {}; + unsigned int nr_mbuf_drop = 0; + will_return(mock_pkt_drop_process, mbuf_drop); + will_return(mock_pkt_drop_process, &nr_mbuf_drop); + + /* first pkt, I->E */ + struct mrb_metadata * mrb_meta_0 = mrbuf_cz_data(mbuf_input[0], MR_NODE_CTRLZONE_ID); + mrb_metadata_clear(mrb_meta_0); + sid_list_init(&mrb_meta_0->sid_list); + mrb_meta_0->port_ingress = 0; + + /* second pkt, E->I */ + struct mrb_metadata * mrb_meta_1 = mrbuf_cz_data(mbuf_input[1], MR_NODE_CTRLZONE_ID); + mrb_metadata_clear(mrb_meta_1); + sid_list_init(&mrb_meta_1->sid_list); + mrb_meta_1->port_ingress = 1; + + /* thrid pkt, from non vwire device, should be drop */ + struct mrb_metadata * mrb_meta_2 = mrbuf_cz_data(mbuf_input[2], MR_NODE_CTRLZONE_ID); + mrb_metadata_clear(mrb_meta_2); + sid_list_init(&mrb_meta_2->sid_list); + mrb_meta_2->port_ingress = 2; + + rte_graph_walk(graph_ptr); + + /* check the count */ + assert_int_equal(nr_mbuf_output, 2); + assert_int_equal(nr_mbuf_drop, 1); + + /* check the mbuf ptr */ + assert_ptr_equal(mbuf_output[0], mbuf_input[0]); + assert_ptr_equal(mbuf_output[1], mbuf_input[1]); + assert_ptr_equal(mbuf_drop[0], mbuf_input[2]); + + /* check the dir */ + assert_int_equal(mrb_meta_0->dir, 0); + assert_int_equal(mrb_meta_1->dir, 1); + + /* check the sid */ + uint16_t mbuf_0_sids[MR_NODE_COMMON_MAX_SID_NUM] = {}; + unsigned int nr_mbuf_0_sids = 0; + + nr_mbuf_0_sids = sid_list_get(&mrb_meta_0->sid_list, mbuf_0_sids, RTE_DIM(mbuf_0_sids)); + assert_int_equal(nr_mbuf_0_sids, 1); + assert_int_equal(mbuf_0_sids[0], 300); + + /* check the second packet */ + uint16_t mbuf_1_sids[MR_NODE_COMMON_MAX_SID_NUM] = {}; + unsigned int nr_mbuf_1_sids = 0; + + nr_mbuf_1_sids = sid_list_get(&mrb_meta_1->sid_list, mbuf_1_sids, RTE_DIM(mbuf_1_sids)); + assert_int_equal(nr_mbuf_1_sids, 1); + assert_int_equal(mbuf_1_sids[0], 300); + + /* release the mbufs */ + rte_pktmbuf_free_bulk(mbuf_output, 2); + rte_pktmbuf_free_bulk(mbuf_drop, 1); + + assert_true(rte_mempool_full(mock_pktmbuf_pool) == 1); +} + +static void testcase_vwire_egress_forward_pkts(void ** state) +{ + struct rte_graph * graph_ptr = rte_graph_lookup("test_vwire_egress"); + assert_non_null(graph_ptr); + + /* alloc the mbuf as input */ + struct rte_mbuf * mbuf_input[2]; + mbuf_input[0] = rte_pktmbuf_alloc(mock_pktmbuf_pool); + mbuf_input[1] = rte_pktmbuf_alloc(mock_pktmbuf_pool); + + assert_non_null(mbuf_input[0]); + assert_non_null(mbuf_input[1]); + + /* set the mbuf data */ + will_return(mock_pkt_input_process, 2); + will_return(mock_pkt_input_process, mbuf_input); + + struct rte_mbuf * mbuf_output[2] = {}; + unsigned int nr_mbuf_output = 0; + + will_return(mock_pkt_output_process, mbuf_output); + will_return(mock_pkt_output_process, &nr_mbuf_output); + + uint16_t sid_list_to_prepend[1] = {300}; + + /* first pkt, I->E */ + struct mrb_metadata * mrb_meta_0 = mrbuf_cz_data(mbuf_input[0], MR_NODE_CTRLZONE_ID); + mrb_metadata_clear(mrb_meta_0); + sid_list_init(&mrb_meta_0->sid_list); + sid_list_prepend(&mrb_meta_0->sid_list, sid_list_to_prepend, RTE_DIM(sid_list_to_prepend)); + mrb_meta_0->cur_sid = 300; + mrb_meta_0->dir = 0; + + /* second pkt, E->I */ + struct mrb_metadata * mrb_meta_1 = mrbuf_cz_data(mbuf_input[1], MR_NODE_CTRLZONE_ID); + mrb_metadata_clear(mrb_meta_1); + sid_list_init(&mrb_meta_1->sid_list); + mrb_meta_1->cur_sid = 300; + mrb_meta_1->dir = 1; + + rte_graph_walk(graph_ptr); + + /* check the count */ + assert_int_equal(nr_mbuf_output, 2); + + /* check the mbuf ptr */ + assert_ptr_equal(mbuf_output[0], mbuf_input[0]); + assert_ptr_equal(mbuf_output[1], mbuf_input[1]); + + /* check the dir */ + assert_int_equal(mrb_meta_0->dir, 0); + assert_int_equal(mrb_meta_1->dir, 1); + assert_int_equal(mrb_meta_0->port_egress, 1); + assert_int_equal(mrb_meta_1->port_egress, 0); + + /* release the buffs */ + rte_pktmbuf_free_bulk(mbuf_output, 2); + assert_true(rte_mempool_full(mock_pktmbuf_pool) == 1); +} + +static int testgroup_vwire_egress_setup(void ** state) +{ + /* mock pkt source to generate mock packets */ + const char * node_patterns[] = { + "mock_pkt_input", + "mock_pkt_output", + "vwire_egress", + }; + + /* create a fake graph */ + struct rte_graph_param graph_param = { + .node_patterns = node_patterns, + .nb_node_patterns = RTE_DIM(node_patterns), + .socket_id = 0, + }; + + /* update the pkt input's next id */ + rte_node_t node_id_pkt_input = rte_node_from_name("mock_pkt_input"); + assert_int_not_equal(node_id_pkt_input, RTE_NODE_ID_INVALID); + + const char * updated_next_node[] = {"vwire_egress"}; + int rc = rte_node_edge_update(node_id_pkt_input, 0, updated_next_node, RTE_DIM(updated_next_node)); + assert_int_equal(rc, 1); + + /* update the node edge */ + rte_node_t node_id_vwire_egress = rte_node_from_name("vwire_egress"); + assert_int_not_equal(node_id_vwire_egress, RTE_NODE_ID_INVALID); + + const char * vwire_egress_updated_next_node[] = { + "mock_pkt_output", + "mock_pkt_drop", + }; + + rc = rte_node_edge_update(node_id_vwire_egress, 0, vwire_egress_updated_next_node, + RTE_DIM(vwire_egress_updated_next_node)); + + assert_int_equal(rc, 2); + + rte_graph_t graph = rte_graph_create("test_vwire_egress", &graph_param); + assert_int_not_equal(graph, RTE_GRAPH_ID_INVALID); + + *state = (void *)(uintptr_t)graph; + return 0; +} + +static int testgroup_vwire_egress_teardown(void ** state) +{ + /* destroy the graph */ + rte_graph_t graph = (uintptr_t)*state; + return rte_graph_destroy(graph); +} + +static int testgroup_vwire_ingress_setup(void **state) +{ + /* mock pkt source to generate mock packets */ + const char * node_patterns[] = { + "mock_pkt_input", + "mock_pkt_output", + "vwire_ingress", + }; + + /* create a fake graph */ + struct rte_graph_param graph_param = { + .node_patterns = node_patterns, + .nb_node_patterns = RTE_DIM(node_patterns), + .socket_id = 0, + }; + + /* update the node edge */ + rte_node_t node_id = rte_node_from_name("vwire_ingress"); + assert_int_not_equal(node_id, RTE_NODE_ID_INVALID); + + rte_node_t next_node_id = rte_node_from_name("mock_pkt_output"); + assert_int_not_equal(next_node_id, RTE_NODE_ID_INVALID); + + const char * updated_next_node[] = { + "mock_pkt_output", + "mock_pkt_drop", + }; + + int rc = rte_node_edge_update(node_id, 0, updated_next_node, RTE_DIM(updated_next_node)); + assert_int_equal(rc, 2); + + rte_graph_t graph = rte_graph_create("test_vwire_ingress", &graph_param); + assert_int_not_equal(graph, RTE_GRAPH_ID_INVALID); + + *state = (void *)(uintptr_t)graph; + return 0; +} + +static int testgroup_vwire_ingress_teardown(void **state) +{ + /* destroy the graph */ + rte_graph_t graph = (uintptr_t)*state; + return rte_graph_destroy(graph); +} + +/* ----------------------------------------------------------------------------------------------------------------- */ +static void testcase_vwire_init_success(void **state) +{ + struct sc_main * mock_sc = *state; + + struct mr_dev_desc * mock_dev_desc_1 = rte_zmalloc(NULL, sizeof(struct mr_dev_desc), 0); + assert_non_null(mock_dev_desc_1); + + struct mr_dev_desc * mock_dev_desc_2 = rte_zmalloc(NULL, sizeof(struct mr_dev_desc), 0); + assert_non_null(mock_dev_desc_2); + + mock_dev_desc_1->port_id = 0; + mock_dev_desc_2->port_id = 1; + + /* find vwire_1 device */ + expect_string(__wrap_mr_dev_desc_lookup, devsym, "vwire_1"); + will_return(__wrap_mr_dev_desc_lookup, mock_dev_desc_1); + + /* find vwire_2 device */ + expect_string(__wrap_mr_dev_desc_lookup, devsym, "vwire_2"); + will_return(__wrap_mr_dev_desc_lookup, mock_dev_desc_2); + + /* expect sid register */ + expect_value(__wrap_forwarder_table_insert, sid, 300); + expect_value(__wrap_forwarder_table_insert, type, FORWARDER_TYPE_VWIRE); + + /* init should success */ + int ret = vwire_init(mock_sc); + assert_int_equal(ret, RT_SUCCESS); + + rte_free(mock_dev_desc_1); + rte_free(mock_dev_desc_2); +} + +static void testcase_vwire_device_not_exist(void **state) +{ + struct sc_main * mock_sc = *state; + + /* cannot find vwire_1 device */ + expect_string(__wrap_mr_dev_desc_lookup, devsym, "vwire_1"); + will_return(__wrap_mr_dev_desc_lookup, NULL); + + /* init should fail */ + int ret = vwire_init(mock_sc); + assert_int_equal(ret, RT_ERR); +} + +static int testgroup_vwire_init_setup(void **state) +{ + struct sc_main * mock_sc = rte_zmalloc(NULL, sizeof(struct sc_main), 0); + assert_non_null(mock_sc); + + remove("test_node_vwire.ini"); + FILE * fp_cfgfile = fopen("test_node_vwire.ini", "w"); + assert_non_null(fp_cfgfile); + + const char * test_cfgfile_content = "[vwire:0]\n" + "vwire_id=0\n" + "interface_int=vwire_1\n" + "interface_ext=vwire_2"; + + fprintf(fp_cfgfile, "%s", test_cfgfile_content); + fclose(fp_cfgfile); + + strcpy(mock_sc->local_cfgfile, "test_node_vwire.ini"); + *state = mock_sc; + return 0; +} + +static int testgroup_vwire_init_teardown(void **state) +{ + struct sc_main * mock_sc = *state; + rte_free(mock_sc); + return 0; +} + +int main(int argc, char *argv[]) +{ + /* generate the eal args */ + static char * eal_args[] = { + "test_node_vwire", + "-c 0x1", + "--no-huge", + "--no-pci", + }; + + /* run the eal with no huge pages */ + int ret = __real_rte_eal_init(RTE_DIM(eal_args), eal_args); + if (ret < 0) + { + __real_rte_exit(EXIT_FAILURE, "Error with EAL initialization\n"); + } + + mock_pktmbuf_pool = rte_pktmbuf_pool_create("test_pktmbuf_pool", 1024, 32, 128, RTE_MBUF_DEFAULT_BUF_SIZE, + SOCKET_ID_ANY); + + const struct CMUnitTest group_vwire_init[] = { + cmocka_unit_test(testcase_vwire_device_not_exist), + cmocka_unit_test(testcase_vwire_init_success), + }; + + const struct CMUnitTest group_vwire_ingress[] = { + cmocka_unit_test(testcase_vwire_ingress_forward_pkts), + }; + + const struct CMUnitTest group_vwire_egress[] = { + cmocka_unit_test(testcase_vwire_egress_forward_pkts), + }; + + cmocka_run_group_tests(group_vwire_init, testgroup_vwire_init_setup, testgroup_vwire_init_teardown); + cmocka_run_group_tests(group_vwire_ingress, testgroup_vwire_ingress_setup, testgroup_vwire_ingress_teardown); + cmocka_run_group_tests(group_vwire_egress, testgroup_vwire_egress_setup, testgroup_vwire_egress_teardown); + rte_eal_cleanup(); +}
\ No newline at end of file diff --git a/support/CMakeLists.txt b/support/CMakeLists.txt index 1dcd29a..82da9d9 100644 --- a/support/CMakeLists.txt +++ b/support/CMakeLists.txt @@ -89,6 +89,19 @@ set_property(TARGET libevent-static-pthreads PROPERTY IMPORTED_LOCATION ${INSTAL set_property(TARGET libevent-static-pthreads PROPERTY IMPORTED_INTERFACE_LINK_LIBRARIES pthread crypto) set_property(TARGET libevent-static-pthreads PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${INSTALL_DIR}/include) +# libcmocka +ExternalProject_Add(cmocka PREFIX cmocka + URL ${CMAKE_CURRENT_SOURCE_DIR}/cmocka-1.1.7.tar.xz + URL_MD5 dc23f4870eb7dfa6da065f3056e815b0 + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=<INSTALL_DIR> -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} -DBUILD_SHARED_LIBS=OFF -DUNIT_TESTING=OFF -DWITH_EXAMPLES=OFF) + +ExternalProject_Get_Property(cmocka INSTALL_DIR) +file(MAKE_DIRECTORY ${INSTALL_DIR}/include) + +add_library(libcmocka STATIC IMPORTED GLOBAL) +add_dependencies(libcmocka cmocka) +set_property(TARGET libcmocka PROPERTY IMPORTED_LOCATION ${INSTALL_DIR}/lib64/libcmocka.a) +set_property(TARGET libcmocka PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${INSTALL_DIR}/include) # Merge multiple patches into one patch file set(DPDK_PATCH_DIR ${CMAKE_CURRENT_SOURCE_DIR}/dpdk) diff --git a/support/cmocka-1.1.7.tar.xz b/support/cmocka-1.1.7.tar.xz Binary files differnew file mode 100644 index 0000000..42aedb0 --- /dev/null +++ b/support/cmocka-1.1.7.tar.xz |
