summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.clang-format1
-rw-r--r--app/CMakeLists.txt47
-rw-r--r--app/include/mrapp.h3
-rw-r--r--app/src/dp_trace.c9
-rw-r--r--app/src/marsio.c82
-rw-r--r--app/src/mrb.c1
-rw-r--r--app/src/rawio.c4
-rw-r--r--app/test/test_marsio_instance_api.c356
-rw-r--r--app/test/test_marsio_rawio_api.c509
-rw-r--r--infra/CMakeLists.txt9
-rw-r--r--infra/src/port_adapter_mapping.c8
-rw-r--r--infra/test/TestDataPathTrace.cc9
-rw-r--r--infra/test/TestLinkDb.cc2
-rw-r--r--service/CMakeLists.txt42
-rw-r--r--service/include/sc_node_common.h2
-rw-r--r--service/src/core.c70
-rw-r--r--service/src/main.c9
-rw-r--r--service/src/node_bfd.c9
-rw-r--r--service/src/node_etherfabric.c2
-rw-r--r--service/src/node_forwarder.c2
-rw-r--r--service/src/node_lb.c2
-rw-r--r--service/src/node_link_aware_injector.c2
-rw-r--r--service/src/node_tera.c2
-rw-r--r--service/src/node_vwire.c23
-rw-r--r--service/test/test_node_mocks.c70
-rw-r--r--service/test/test_node_vwire.c414
-rw-r--r--support/CMakeLists.txt13
-rw-r--r--support/cmocka-1.1.7.tar.xzbin0 -> 84064 bytes
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(&reg_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, &param_cpu_set);
+
+ int ret = marsio_option_set(instance, MARSIO_OPT_THREAD_MASK_IN_CPUSET, &param_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, &param_cpu_set_get, sizeof(param_cpu_set_get));
+ assert_true(CPU_EQUAL(&param_cpu_set, &param_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, &param_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, &param_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, &param_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, &param_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
new file mode 100644
index 0000000..42aedb0
--- /dev/null
+++ b/support/cmocka-1.1.7.tar.xz
Binary files differ