diff options
Diffstat (limited to 'infra/test/TestDataPathTrace.c')
| -rw-r--r-- | infra/test/TestDataPathTrace.c | 468 |
1 files changed, 468 insertions, 0 deletions
diff --git a/infra/test/TestDataPathTrace.c b/infra/test/TestDataPathTrace.c new file mode 100644 index 0000000..6d0ff34 --- /dev/null +++ b/infra/test/TestDataPathTrace.c @@ -0,0 +1,468 @@ + +#include <setjmp.h> +#include <stdarg.h> +#include <stddef.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <cmocka.h> + +#include <rte_common.h> +#include <rte_eal.h> +#include <rte_errno.h> +#include <rte_malloc.h> + +#include "dp_trace.h" +#include "ldbc.h" +#include "mrb_define.h" + +unsigned int g_logger_to_stdout = 1; +unsigned int g_logger_level = LOG_DEBUG; +struct dp_trace_process * trace; +struct rte_mempool * mempool; + +/* 73 Ether/IPv4/UDP/G-VxLan/Ether/VLAN/IPv4/TCP + + Outer Ether e8:4d:d0:ca:3a:1f -> 58:69:6c:6f:96:f3 + Outer IPv4 1.1.15.100 -> 10.0.4.120 + Outer UDP 60014 -> 4789 + + Outer Ether 64:f6:9d:5f:b9:76 -> a4:93:4c:c6:e5:5f + Inner IPv4 125.33.49.137 -> 39.66.162.89 + Inner TCP 28402→11235 +*/ + +/* Frame (114 bytes) */ +static const unsigned char pkt73[114] = { + 0xe8, 0x4d, 0xd0, 0xca, 0x3a, 0x1f, 0x58, 0x69, /* .M..:.Xi */ + 0x6c, 0x6f, 0x96, 0xf3, 0x08, 0x00, 0x45, 0x00, /* lo....E. */ + 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0xfd, 0x11, /* .d...... */ + 0x9e, 0xac, 0x01, 0x01, 0x0f, 0x64, 0x0a, 0x00, /* .....d.. */ + 0x04, 0x78, 0xea, 0x6e, 0x12, 0xb5, 0x00, 0x50, /* .x.n...P */ + 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x06, 0x50, /* .......P */ + 0x01, 0x00, 0x64, 0xf6, 0x9d, 0x5f, 0xb9, 0x76, /* ..d.._.v */ + 0xa4, 0x93, 0x4c, 0xc6, 0xe5, 0x5f, 0x81, 0x00, /* ..L.._.. */ + 0x00, 0x01, 0x08, 0x00, 0x45, 0x00, 0x00, 0x28, /* ....E..( */ + 0x59, 0x6f, 0x40, 0x00, 0x7b, 0x06, 0x2e, 0x1b, /* Yo@.{... */ + 0x7d, 0x21, 0x31, 0x89, 0x27, 0x42, 0xa2, 0x59, /* }!1.'B.Y */ + 0x6e, 0xf2, 0x2b, 0xe3, 0xa5, 0x40, 0xd8, 0x7f, /* n.+..@.. */ + 0x9d, 0x5c, 0x74, 0xba, 0x50, 0x10, 0xfb, 0xb8, /* .\t.P... */ + 0x11, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* .)...... */ + 0x00, 0x00 /* .. */ +}; + +int contains_substring(const char * str, const char * substr, size_t len); + +static int setup_testcase(void ** state) +{ + const char * argv[] = {"TestDataPathTrace", "-c", "0x1", "--no-huge", "-m", "512", "--no-pci"}; + if (rte_eal_init(RTE_DIM(argv), (char **)argv) < 0) + { + rte_exit(EXIT_FAILURE, "failed at rte_eal_init()"); + return 1; + } + return 0; +} + +static int teardown_testCase(void ** state) +{ + rte_eal_cleanup(); + return 0; +} + +static int setup(void ** state) +{ + // create trace + trace = dp_trace_process_create(DP_TRACE_PROCESS_MARSIO); + trace->inst->enable = true; + unsigned int sz_align_priv = RTE_ALIGN(sizeof(struct mrb_metadata), RTE_MBUF_PRIV_ALIGN); + mempool = rte_pktmbuf_pool_create("dp_trace_dump_pool", 16, 0, sz_align_priv, + DP_TRACE_RECORD_SIZE + RTE_MBUF_DEFAULT_BUF_SIZE, rte_socket_id()); + return 0; +} + +void dp_trace_process_destroy(struct dp_trace_process * trace, enum dp_trace_process_type process_tpye) +{ + // This function is for unit testing only. This instance created by marsio or app should not be deleted + // manually. It accompanies the entire life cycle of the process. + if (process_tpye == DP_TRACE_PROCESS_MARSIO) + { + rte_mempool_free(trace->inst->pool); + rte_mempool_free(mempool); + for (unsigned int i = 0; i < trace->inst->nr_ring; i++) + { + rte_ring_free(trace->inst->ring[i]); + } + FREE(trace->inst); + FREE(trace); + } + else + { + FREE(trace); + } +} + +static int teardown(void ** state) +{ + dp_trace_process_destroy(trace, DP_TRACE_PROCESS_MARSIO); + return 0; +} + +struct rte_mbuf * mbuf_construct(const unsigned char * pkt, unsigned int len) +{ + if (trace == NULL) + return NULL; + + struct rte_mbuf * pkt_mbuf = rte_pktmbuf_alloc(mempool); + unsigned int sz_align_priv = RTE_ALIGN(sizeof(struct mrb_metadata), RTE_MBUF_PRIV_ALIGN); + + uint16_t data_off = sizeof(struct rte_mbuf) + sz_align_priv; + unsigned char * data_addr = (unsigned char *)pkt_mbuf->buf_addr + data_off; + memcpy(data_addr, pkt, len); + pkt_mbuf->data_off = data_off; + pkt_mbuf->data_len = len; + pkt_mbuf->pkt_len = len; + pkt_mbuf->nb_segs = 1; + pkt_mbuf->next = NULL; + + // parse mbuf + struct pkt_parser _pkt_handler; + struct pkt_parser_result _pkt_result; + pkt_parser_init(&_pkt_handler, &_pkt_result, LAYER_TYPE_ALL, MR_PKT_PARSER_LAYERS_MAX); + pkt_parser_exec(&_pkt_handler, pkt_mbuf); + + struct mrb_metadata * mrb_meta = (struct mrb_metadata *)mrbuf_cz_data(pkt_mbuf, 1); + struct pkt_parser_result * pkt_parser_result = &mrb_meta->pkt_parser_result; + memcpy(pkt_parser_result, &_pkt_result, sizeof(struct pkt_parser_result)); + mrb_meta->dp_trace_buffer = NULL; + + return pkt_mbuf; +} + +static void testcase_packet_construct(void ** state) +{ + struct rte_mbuf * pkt73_mbuf = mbuf_construct(pkt73, sizeof(pkt73)); + struct mrb_metadata * mrb_meta = (struct mrb_metadata *)mrbuf_cz_data(pkt73_mbuf, 1); + + struct rte_mbuf * mbuf = (struct rte_mbuf *)rte_zmalloc(NULL, sizeof(struct rte_mbuf), 0); + mbuf->buf_len = sizeof(pkt73); + mbuf->buf_addr = (void *)(const char *)pkt73; + mbuf->data_off = 0; + mbuf->data_len = sizeof(pkt73); + mbuf->pkt_len = sizeof(pkt73); + mbuf->nb_segs = 1; + mbuf->next = NULL; + + struct pkt_parser _pkt_handler; + struct pkt_parser_result _pkt_parser; + pkt_parser_init(&_pkt_handler, &_pkt_parser, LAYER_TYPE_ALL, MR_PKT_PARSER_LAYERS_MAX); + pkt_parser_exec(&_pkt_handler, mbuf); + unsigned int inner_ether_offset = _pkt_parser.layers[4].offset; + + assert_true(mrb_meta->pkt_parser_result.layers[4].offset == inner_ether_offset); + + FREE(mbuf); + infra_rte_pktmbuf_free(pkt73_mbuf); +} + +static void testcase_instance_create(void ** state) +{ + assert_true(trace->inst != NULL); +} + +static void testcase_job_init(void ** state) +{ + int n; + struct dp_trace_job_desc desc = { + .enable = true, + .measurement_type = DP_TRACE_MEASUREMENT_TYPE_TRACE, + .rule_index = 0, + .bpf_expr = "ether host 64:f6:9d:5f:b9:76", + .pkt_cnt_max = 10, + .sampling = 1, + }; + n = dp_trace_job_add(trace, &desc); + assert_true(n >= 0); + assert_true(trace->inst->job_ctx[0].used == true); +} + +static void testcase_job_destroy(void ** state) +{ + struct dp_trace_job_desc desc = { + .enable = true, + .measurement_type = DP_TRACE_MEASUREMENT_TYPE_TRACE, + .rule_index = 0, + .bpf_expr = "ether host 64:f6:9d:5f:b9:76", + .pkt_cnt_max = 10, + .sampling = 1, + }; + dp_trace_job_add(trace, &desc); + + struct dp_trace_job_desc desc_2 = { + .enable = true, + .measurement_type = DP_TRACE_MEASUREMENT_TYPE_TRACE, + .rule_index = 1, + .bpf_expr = "vlan && ip src 125.33.49.137", + .pkt_cnt_max = 10, + .sampling = 1, + }; + dp_trace_job_add(trace, &desc_2); + + dp_trace_jobs_destroy(trace, 1 | 1 << 1); + + assert_true(trace->inst->job_ctx[0].used == false); + assert_true(trace->inst->job_ctx[1].used == false); +} + +static void testcase_job_bpf_match(void ** state) +{ + struct rte_mbuf * pkt73_mbuf = mbuf_construct(pkt73, sizeof(pkt73)); + struct mrb_metadata * mrb_meta = (struct mrb_metadata *)mrbuf_cz_data(pkt73_mbuf, 1); + unsigned int offset = mrb_meta->pkt_parser_result.layers[4].offset; + + struct dp_trace_job_desc desc = { + .enable = true, + .measurement_type = DP_TRACE_MEASUREMENT_TYPE_TRACE, + .rule_index = 0, + .bpf_expr = "ether host 64:f6:9d:5f:b9:76", + .pkt_cnt_max = 10, + .sampling = 1, + }; + dp_trace_job_add(trace, &desc); + + struct dp_trace_job_desc desc_2 = { + .enable = true, + .measurement_type = DP_TRACE_MEASUREMENT_TYPE_TRACE, + .rule_index = 1, + .bpf_expr = "vlan && ip src 125.33.49.137", + .pkt_cnt_max = 10, + .sampling = 1, + }; + dp_trace_job_add(trace, &desc_2); + + dp_trace_filter_exec(trace, pkt73_mbuf, offset, 0); + u_int16_t ret = dp_trace_job_id_bitmap_get(trace, pkt73_mbuf); + assert_true(ret == 3); + + struct dp_trace_buffer * dp_trace_buffer = (struct dp_trace_buffer *)mrb_meta->dp_trace_buffer; + assert_true(dp_trace_buffer != NULL); + assert_true(dp_trace_buffer->jobs == 3); + + infra_rte_pktmbuf_free(pkt73_mbuf); +} + +static void testcase_job_bpf_match_external_and_internal(void ** state) +{ + struct rte_mbuf * pkt73_mbuf = mbuf_construct(pkt73, sizeof(pkt73)); + struct mrb_metadata * mrb_meta = (struct mrb_metadata *)mrbuf_cz_data(pkt73_mbuf, 1); + + struct dp_trace_job_desc desc = { + .enable = true, + .measurement_type = DP_TRACE_MEASUREMENT_TYPE_TRACE, + .rule_index = 0, + .bpf_expr = "ip src 1.1.15.100", + .pkt_cnt_max = 10, + .sampling = 1, + }; + dp_trace_job_add(trace, &desc); + + struct dp_trace_job_desc desc_2 = { + .enable = true, + .measurement_type = DP_TRACE_MEASUREMENT_TYPE_TRACE, + .rule_index = 1, + .bpf_expr = "vlan && ip src 125.33.49.137", + .pkt_cnt_max = 10, + .sampling = 1, + }; + dp_trace_job_add(trace, &desc_2); + + dp_trace_filter_exec(trace, pkt73_mbuf, 0, 0); + u_int16_t ret = dp_trace_job_id_bitmap_get(trace, pkt73_mbuf); + assert_true(ret == 3); + + struct dp_trace_buffer * dp_trace_buffer = (struct dp_trace_buffer *)mrb_meta->dp_trace_buffer; + assert_true(dp_trace_buffer != NULL); + assert_true(dp_trace_buffer->jobs == 3); + + infra_rte_pktmbuf_free(pkt73_mbuf); +} + +static void testcase_job_bpf_unmatch(void ** state) +{ + struct rte_mbuf * pkt73_mbuf = mbuf_construct(pkt73, sizeof(pkt73)); + struct mrb_metadata * mrb_meta = (struct mrb_metadata *)mrbuf_cz_data(pkt73_mbuf, 1); + unsigned int offset = mrb_meta->pkt_parser_result.layers[4].offset; + + struct dp_trace_job_desc desc = { + .enable = true, + .measurement_type = DP_TRACE_MEASUREMENT_TYPE_TRACE, + .rule_index = 0, + .bpf_expr = "vlan && ip src 127.0.0.1", + .pkt_cnt_max = 10, + .sampling = 1, + }; + dp_trace_job_add(trace, &desc); + + dp_trace_filter_exec(trace, pkt73_mbuf, offset, 0); + u_int16_t ret = dp_trace_job_id_bitmap_get(trace, pkt73_mbuf); + assert_true(ret == 0); + + assert_true(mrb_meta->dp_trace_buffer == NULL); + + infra_rte_pktmbuf_free(pkt73_mbuf); +} + +static void testcase_job_emit_trace(void ** state) +{ + struct rte_mbuf * pkt73_mbuf = mbuf_construct(pkt73, sizeof(pkt73)); + struct mrb_metadata * mrb_meta = (struct mrb_metadata *)mrbuf_cz_data(pkt73_mbuf, 1); + + struct dp_trace_job_desc desc = { + .enable = true, + .measurement_type = DP_TRACE_MEASUREMENT_TYPE_TRACE, + .rule_index = 1, + .bpf_expr = "ether host 64:f6:9d:5f:b9:76", + .pkt_cnt_max = 10, + .sampling = 1, + }; + dp_trace_job_add(trace, &desc); + + mrb_meta->packet_create_from_nf = 1; + memset(&mrb_meta->pkt_parser_result, 0, sizeof(mrb_meta->pkt_parser_result)); + + dp_trace_filter_exec(trace, pkt73_mbuf, 0, rte_lcore_id()); + + struct dp_trace_record_meta meta = {DP_TRACE_MEASUREMENT_TYPE_TRACE, "test", "emit", NULL}; + dp_trace_record_emit_str(trace, pkt73_mbuf, rte_lcore_id(), &meta, "abc"); + + struct dp_trace_record_meta meta_2 = {DP_TRACE_MEASUREMENT_TYPE_TRACE, "test", "emit", NULL}; + dp_trace_record_emit_str(trace, pkt73_mbuf, rte_lcore_id(), &meta_2, "def"); + + struct dp_trace_buffer * dp_trace_buffer = (struct dp_trace_buffer *)mrb_meta->dp_trace_buffer; + + char * cur = dp_trace_buffer->buffer; + struct dp_trace_record_header * record_header = (struct dp_trace_record_header *)(cur); + char * str = cur + sizeof(struct dp_trace_record_header); + unsigned int str_len = record_header->recode_len; + assert_true(contains_substring(str, "abc", str_len) == 1); + + cur += sizeof(struct dp_trace_record_header) + str_len; + record_header = (struct dp_trace_record_header *)(cur); + str = cur + sizeof(struct dp_trace_record_header); + assert_true(contains_substring(str, "def", str_len) == 1); + + // Excessive content will not cause buffer overflow + char big_buf[DP_TRACE_RECORD_SIZE] = {}; + memset(big_buf, 'a', DP_TRACE_RECORD_SIZE - 1); + dp_trace_record_emit_str(trace, pkt73_mbuf, rte_lcore_id(), &meta_2, big_buf); + + assert_true(dp_trace_buffer->buffer_used <= DP_TRACE_RECORD_SIZE); + + infra_rte_pktmbuf_free(pkt73_mbuf); +} + +static void testcase_job_strip_to_ring(void ** state) +{ + struct rte_mbuf * pkt73_mbuf = mbuf_construct(pkt73, sizeof(pkt73)); + struct mrb_metadata * mrb_meta = (struct mrb_metadata *)mrbuf_cz_data(pkt73_mbuf, 1); + unsigned int offset = mrb_meta->pkt_parser_result.layers[4].offset; + + struct dp_trace_job_desc desc = { + .enable = true, + .measurement_type = DP_TRACE_MEASUREMENT_TYPE_TRACE, + .rule_index = 0, + .bpf_expr = "ether host 64:f6:9d:5f:b9:76", + .pkt_cnt_max = 10, + .sampling = 1, + }; + dp_trace_job_add(trace, &desc); + + dp_trace_filter_exec(trace, pkt73_mbuf, offset, rte_lcore_id()); + + struct dp_trace_record_meta meta = {DP_TRACE_MEASUREMENT_TYPE_TRACE, "test", "emit", NULL}; + dp_trace_record_emit_str(trace, pkt73_mbuf, rte_lcore_id(), &meta, "abc"); + + dp_trace_record_write(trace, pkt73_mbuf, rte_lcore_id()); + + unsigned int trace_record_cnt = 0; + for (unsigned int i = 0; i < trace->nr_ring; i++) + { + trace_record_cnt += rte_ring_count(trace->ring[i]); + } + assert_true(trace_record_cnt == 1); + + infra_rte_pktmbuf_free(pkt73_mbuf); +} + +static void testcase_job_max_record_count(void ** state) +{ + unsigned int lcore_id = rte_lcore_id(); + + struct dp_trace_job_desc desc = { + .enable = true, + .measurement_type = DP_TRACE_MEASUREMENT_TYPE_TRACE, + .rule_index = 0, + .bpf_expr = "ether host 64:f6:9d:5f:b9:76", + .pkt_cnt_max = 2, + .sampling = 1, + }; + dp_trace_job_add(trace, &desc); + + struct rte_mbuf * pkt73_mbuf = mbuf_construct(pkt73, sizeof(pkt73)); + dp_trace_filter_exec(trace, pkt73_mbuf, 0, 0); + infra_rte_pktmbuf_free(pkt73_mbuf); + + assert_true(trace->statistics[lcore_id].record_buf_alloc_success == 1); + + pkt73_mbuf = mbuf_construct(pkt73, sizeof(pkt73)); + dp_trace_filter_exec(trace, pkt73_mbuf, 0, 0); + infra_rte_pktmbuf_free(pkt73_mbuf); + + assert_true(trace->statistics[lcore_id].record_buf_alloc_success == 2); + + pkt73_mbuf = mbuf_construct(pkt73, sizeof(pkt73)); + dp_trace_filter_exec(trace, pkt73_mbuf, 0, 0); + infra_rte_pktmbuf_free(pkt73_mbuf); + + assert_true(trace->statistics[lcore_id].record_buf_alloc_success == 2); +} + +int main(int argc, char * argv[]) +{ + + const struct CMUnitTest testcase_trace[] = { + cmocka_unit_test_setup_teardown(testcase_packet_construct, setup, teardown), + cmocka_unit_test_setup_teardown(testcase_instance_create, setup, teardown), + cmocka_unit_test_setup_teardown(testcase_job_init, setup, teardown), + cmocka_unit_test_setup_teardown(testcase_job_destroy, setup, teardown), + cmocka_unit_test_setup_teardown(testcase_job_bpf_match, setup, teardown), + cmocka_unit_test_setup_teardown(testcase_job_bpf_match_external_and_internal, setup, teardown), + cmocka_unit_test_setup_teardown(testcase_job_bpf_unmatch, setup, teardown), + cmocka_unit_test_setup_teardown(testcase_job_emit_trace, setup, teardown), + cmocka_unit_test_setup_teardown(testcase_job_strip_to_ring, setup, teardown), + cmocka_unit_test_setup_teardown(testcase_job_max_record_count, setup, teardown), + }; + + // 0 on success, or the number of failed tests. + int ret = cmocka_run_group_tests(testcase_trace, setup_testcase, teardown_testCase); + + // Pass the return value to ctest. Report an error if it is non-zero + return ret; +} + +//////////////////////////////////// helper function //////////////////////////////////// + +int contains_substring(const char * str, const char * substr, size_t len) +{ + size_t substr_len = strlen(substr); + for (size_t i = 0; i <= len - substr_len; i++) + { + if (strncmp(&str[i], substr, substr_len) == 0) + { + return 1; + } + } + return -1; +}
\ No newline at end of file |
