#include #include #include #include #include #include #include #include #include #include #include #include struct bfd_node_main; struct bfd_session; struct bfd_session_handle; struct bfd_test_main { struct sc_main * mock_sc; rte_graph_t graph; struct bfd_node_main * bfd_node_main; }; extern int bfd_init(struct sc_main * sc); extern void bfd_deinit(struct sc_main * sc); extern int bfd_node_main_delete(struct bfd_node_main * bfd_main); extern struct bfd_node_main * bfd_node_main_create(uint16_t nr_graphs); extern struct bfd_node_main * g_bfd_node_main_get(void); extern int g_bfd_node_main_set(struct bfd_node_main * bfd_node_main); extern struct bfd_session_handle * bfd_session_handle_create(uint16_t max_sessions); extern int bfd_session_handle_delete(struct bfd_session_handle * bfd_session_handle); extern struct bfd_session_handle * bfd_session_handle_get(struct bfd_node_main * bfd_main, uint16_t graph_id); extern int bfd_session_handle_is_empty(struct bfd_session_handle * bfd_session_handle); extern int bfd_session_handle_is_full(struct bfd_session_handle * bfd_session_handle); extern struct bfd_session * bfd_session_lookup(struct bfd_session_handle * bfd_session_handle, uint32_t ipv4_address); extern struct bfd_session * bfd_session_add(struct bfd_session_handle * bfd_session_handle, uint32_t ipv4_address); extern int bfd_session_update(struct bfd_session * bfd_session); extern int bfd_session_delete(struct bfd_session_handle * bfd_session_handle, uint32_t ipv4_address); extern void eth_header_construct(struct rte_ether_hdr * eth_hdr, struct rte_ether_addr * src_mac, struct rte_ether_addr * dst_mac, uint16_t eth_type); extern int ipv4_header_construct(struct rte_ipv4_hdr * ipv4_hdr, const char * src_ip, const char * dst_ip, uint8_t proto, uint16_t payload_length); extern void udp_header_construct(struct rte_udp_hdr * udp_hdr, uint16_t src_port, uint16_t dst_port, uint16_t length); extern void bfd_header_construct(struct bfd_hdr * bfd_hdr, uint32_t * my_discriminator, uint32_t * your_discriminator, uint8_t state); extern const char * create_config_file(const char * content); static struct rte_mempool * mock_pktmbuf_pool = NULL; /* ------------------------------------------- Test group setup/teardown ------------------------------------------- */ static int testgroup_bfd_init_setup(void ** state) { struct sc_main * mock_sc = rte_zmalloc(NULL, sizeof(struct sc_main), 0); assert_non_null(mock_sc); const char * test_cfgfile_content = "[bfd]\n" "disc_method=0"; const char * filename = create_config_file(test_cfgfile_content); assert_non_null(filename); strcpy(mock_sc->local_cfgfile, filename); mock_sc->nr_io_thread = 1; *state = mock_sc; return 0; } static int testgroup_bfd_init_teardown(void ** state) { struct sc_main * mock_sc = *state; rte_free(mock_sc); return 0; } static int testgroup_bfd_discriminator_method_rfc_setup(void ** state) { /* mock pkt source to generate mock packets */ const char * node_patterns[] = { "mock_pkt_input", "mock_pkt_output", "bfd", }; /* 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[] = {"bfd"}; 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_bfd = rte_node_from_name("bfd"); assert_int_not_equal(node_id_bfd, RTE_NODE_ID_INVALID); const char * bfd_updated_next_node[] = { "mock_pkt_drop", "mock_pkt_output", }; rc = rte_node_edge_update(node_id_bfd, 0, bfd_updated_next_node, RTE_DIM(bfd_updated_next_node)); assert_int_equal(rc, 2); rte_graph_t graph = rte_graph_create("test_bfd", &graph_param); assert_int_not_equal(graph, RTE_GRAPH_ID_INVALID); struct sc_main * mock_sc = rte_zmalloc(NULL, sizeof(struct sc_main), 0); assert_non_null(mock_sc); mock_sc->nr_io_thread = 1; const char * test_cfgfile_content = "[bfd]\n" "disc_method=0"; const char * filename = create_config_file(test_cfgfile_content); assert_non_null(filename); strcpy(mock_sc->local_cfgfile, filename); int ret = bfd_init(mock_sc); assert_int_equal(ret, RT_SUCCESS); struct bfd_node_main * bfd_node_main = g_bfd_node_main_get(); assert_non_null(bfd_node_main); struct bfd_test_main * bfd_test_main = rte_zmalloc(NULL, sizeof(struct bfd_test_main), 0); assert_non_null(bfd_test_main); bfd_test_main->mock_sc = mock_sc; bfd_test_main->graph = graph; bfd_test_main->bfd_node_main = bfd_node_main; *state = bfd_test_main; return 0; } static int testgroup_bfd_discriminator_method_rfc_teardown(void ** state) { struct bfd_test_main * bfd_test_main = *state; /* deinitialize the bfd */ bfd_deinit(bfd_test_main->mock_sc); assert_ptr_equal(g_bfd_node_main_get(), NULL); /* free the mock_sc */ rte_free(bfd_test_main->mock_sc); /* destroy the graph */ rte_graph_destroy(bfd_test_main->graph); /* free the bfd_test_main */ rte_free(bfd_test_main); return 0; } static int testgroup_bfd_discriminator_method_flipping_setup(void ** state) { /* mock pkt source to generate mock packets */ const char * node_patterns[] = { "mock_pkt_input", "mock_pkt_output", "bfd", }; /* 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[] = {"bfd"}; 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_bfd = rte_node_from_name("bfd"); assert_int_not_equal(node_id_bfd, RTE_NODE_ID_INVALID); const char * bfd_updated_next_node[] = { "mock_pkt_drop", "mock_pkt_output", }; rc = rte_node_edge_update(node_id_bfd, 0, bfd_updated_next_node, RTE_DIM(bfd_updated_next_node)); assert_int_equal(rc, 2); rte_graph_t graph = rte_graph_create("test_bfd", &graph_param); assert_int_not_equal(graph, RTE_GRAPH_ID_INVALID); struct sc_main * mock_sc = rte_zmalloc(NULL, sizeof(struct sc_main), 0); assert_non_null(mock_sc); mock_sc->nr_io_thread = 1; const char * test_cfgfile_content = "[bfd]\n" "disc_method=1"; const char * filename = create_config_file(test_cfgfile_content); assert_non_null(filename); strcpy(mock_sc->local_cfgfile, filename); int ret = bfd_init(mock_sc); assert_int_equal(ret, RT_SUCCESS); struct bfd_node_main * bfd_node_main = g_bfd_node_main_get(); assert_non_null(bfd_node_main); struct bfd_test_main * bfd_test_main = rte_zmalloc(NULL, sizeof(struct bfd_test_main), 0); assert_non_null(bfd_test_main); bfd_test_main->mock_sc = mock_sc; bfd_test_main->graph = graph; bfd_test_main->bfd_node_main = bfd_node_main; *state = bfd_test_main; return 0; } static int testgroup_bfd_discriminator_method_flipping_teardown(void ** state) { struct bfd_test_main * bfd_test_main = *state; /* deinitialize the bfd */ bfd_deinit(bfd_test_main->mock_sc); assert_ptr_equal(g_bfd_node_main_get(), NULL); /* free the mock_sc */ rte_free(bfd_test_main->mock_sc); /* destroy the graph */ rte_graph_destroy(bfd_test_main->graph); /* free the bfd_test_main */ rte_free(bfd_test_main); return 0; } /* --------------------------------------------------- Test case --------------------------------------------------- */ /* Test Case: BFD initialization success */ static void testcase_bfd_init_success(void ** state) { struct sc_main * mock_sc = *state; int rc = bfd_init(mock_sc); assert_int_equal(rc, RT_SUCCESS); } /* Test Case: BFD Deinitialize success */ static void testcase_bfd_deinit_success(void ** state) { struct sc_main * mock_sc = *state; bfd_deinit(mock_sc); assert_ptr_equal(g_bfd_node_main_get(), NULL); } /* Test Case: BFD node main API in a successful scenario */ static void testcase_bfd_node_main_api_success(void ** state) { struct bfd_node_main * bfd_node_main = bfd_node_main_create(RTE_MAX_LCORE); assert_non_null(bfd_node_main); g_bfd_node_main_set(bfd_node_main); struct bfd_node_main * bfd_node_main_get = g_bfd_node_main_get(); assert_non_null(bfd_node_main_get); int ret = bfd_node_main_delete(bfd_node_main); assert_int_equal(ret, RT_SUCCESS); g_bfd_node_main_set(NULL); bfd_node_main_get = g_bfd_node_main_get(); assert_ptr_equal(bfd_node_main_get, NULL); } /* Test Case: BFD node main API in a failure scenario */ static void testcase_bfd_node_main_api_failure(void ** state) { struct bfd_node_main * bfd_node_main = bfd_node_main_create(0); assert_null(bfd_node_main); int ret = bfd_node_main_delete(bfd_node_main); assert_int_equal(ret, RT_ERR); ret = g_bfd_node_main_set(bfd_node_main); assert_int_equal(ret, RT_SUCCESS); struct bfd_node_main * bfd_node_main_get = g_bfd_node_main_get(); assert_ptr_equal(bfd_node_main_get, NULL); } /* Test Case: BFD session handle API in a successful scenario */ static void testcase_bfd_session_handle_api_success(void ** state) { /* create the bfd session handle */ struct bfd_session_handle * bfd_session_handle = bfd_session_handle_create(UINT16_MAX); assert_non_null(bfd_session_handle); /* check the session handle is empty */ int ret = bfd_session_handle_is_empty(bfd_session_handle); assert_int_equal(ret, 1); /* add the bfd session */ for (uint32_t i = 0; i < UINT16_MAX; i++) { struct bfd_session * bfd_session = bfd_session_add(bfd_session_handle, i); assert_non_null(bfd_session); } /* check the session handle is full */ ret = bfd_session_handle_is_empty(bfd_session_handle); assert_int_equal(ret, 0); ret = bfd_session_handle_is_full(bfd_session_handle); assert_int_equal(ret, 1); /* lookup and update the bfd session */ for (uint32_t i = 0; i < UINT16_MAX; i++) { struct bfd_session * bfd_session = bfd_session_lookup(bfd_session_handle, i); assert_non_null(bfd_session); ret = bfd_session_update(bfd_session); assert_int_equal(ret, RT_SUCCESS); } /* delete the bfd session */ for (uint32_t i = 0; i < UINT16_MAX; i++) { ret = bfd_session_delete(bfd_session_handle, i); assert_int_equal(ret, RT_SUCCESS); } /* check the session handle is empty */ ret = bfd_session_handle_is_empty(bfd_session_handle); assert_int_equal(ret, 1); /* delete the bfd session handle */ ret = bfd_session_handle_delete(bfd_session_handle); assert_int_equal(ret, RT_SUCCESS); } /* Test Case: BFD session handle API in a failure scenario */ static void testcase_bfd_session_handle_api_failure(void ** state) { /* create the bfd session handle */ struct bfd_session_handle * bfd_session_handle = bfd_session_handle_create(0); assert_null(bfd_session_handle); /* delete the bfd session handle */ int ret = bfd_session_handle_delete(bfd_session_handle); assert_int_equal(ret, RT_ERR); bfd_session_handle = bfd_session_handle_create(1); assert_non_null(bfd_session_handle); /* add the bfd session */ struct bfd_session * bfd_session = bfd_session_add(bfd_session_handle, 1); assert_non_null(bfd_session); /* add the bfd session again */ bfd_session = bfd_session_add(bfd_session_handle, 2); assert_null(bfd_session); /* delete the bfd session */ ret = bfd_session_delete(bfd_session_handle, 2); assert_int_equal(ret, RT_ERR); /* delete the bfd session again */ ret = bfd_session_delete(bfd_session_handle, 1); assert_int_equal(ret, RT_SUCCESS); /* lookup the bfd session */ bfd_session = bfd_session_lookup(bfd_session_handle, 1); assert_null(bfd_session); /* delete the bfd session handle */ ret = bfd_session_handle_delete(bfd_session_handle); assert_int_equal(ret, RT_SUCCESS); } /* Test Case: rfc 5881 */ /* * BFD State Interaction Diagram * * A B * -------- -------- * DOWN DOWN * | | * | down->init | * |-----------------------------------| * | | * | | * | BFD DOWN | * |-------------------------> | * | | * | | * | BFD INIT | * |<------------------------- | * | | * | | * | BFD UP | * |-------------------------> | * | | * | | * | BFD UP | * |<------------------------- | * UP UP * * Legend: * - BFD DOWN: BFD Down state packet * - BFD INIT: BFD Init state packet * - BFD UP: BFD Up state packet * - XX->YY: State change from XX to YY */ static void testcase_bfd_rfc5881(void ** state) { struct rte_graph * graph_ptr = rte_graph_lookup("test_bfd"); assert_non_null(graph_ptr); /* alloc the mbuf as input */ struct rte_mbuf * mbuf_input[1]; mbuf_input[0] = rte_pktmbuf_alloc(mock_pktmbuf_pool); assert_non_null(mbuf_input[0]); /* set the return value for the mock function */ will_return(mock_pkt_input_process, 1); will_return(mock_pkt_input_process, mbuf_input); struct rte_mbuf * mbuf_output[1] = {}; unsigned int nr_mbuf_output = 0; will_return(mock_pkt_output_process, mbuf_output); will_return(mock_pkt_output_process, &nr_mbuf_output); /* set mbuf pkt_len */ mbuf_input[0]->data_len = sizeof(struct rte_ether_hdr) + sizeof(struct rte_ipv4_hdr) + sizeof(struct rte_udp_hdr) + sizeof(struct bfd_hdr); mbuf_input[0]->pkt_len = mbuf_input[0]->data_len; /* prepare the bfd packet for initialization */ struct rte_ether_hdr * ether_hdr = rte_pktmbuf_mtod(mbuf_input[0], struct rte_ether_hdr *); struct rte_ipv4_hdr * ipv4_hdr = (struct rte_ipv4_hdr *)(ether_hdr + 1); struct rte_udp_hdr * udp_hdr = (struct rte_udp_hdr *)(ipv4_hdr + 1); struct bfd_hdr * bfd_hdr = (struct bfd_hdr *)(udp_hdr + 1); /* * 1. bfd down to init */ /* set the ether header */ struct rte_ether_addr dst_mac = {.addr_bytes = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66}}; struct rte_ether_addr src_mac = {.addr_bytes = {0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff}}; eth_header_construct(ether_hdr, &src_mac, &dst_mac, RTE_ETHER_TYPE_IPV4); /* set the ipv4 header */ ipv4_header_construct(ipv4_hdr, NULL, NULL, IPPROTO_UDP, sizeof(struct rte_udp_hdr) + sizeof(struct bfd_hdr)); /* set the udp header */ udp_header_construct(udp_hdr, 3784, 3784, sizeof(struct bfd_hdr)); /* set the bfd header */ uint32_t discriminator_local = 0x12345678; bfd_header_construct(bfd_hdr, &discriminator_local, NULL, BFD_STATE_DOWN); struct mrb_metadata * mrb_meta = mrbuf_cz_data(mbuf_input[0], MR_NODE_CTRLZONE_ID); mrb_metadata_clear(mrb_meta); mrb_meta->port_ingress = 1; /* prepare to parse the ingress pkt */ struct pkt_parser pkt_parser; pkt_parser_init(&pkt_parser, &mrb_meta->pkt_parser_result, LAYER_TYPE_ALL, MR_PKT_PARSER_LAYERS_MAX); pkt_parser_exec(&pkt_parser, mbuf_input[0]); rte_graph_walk(graph_ptr); /* check the count */ assert_int_equal(nr_mbuf_output, 1); /* check the mbuf ptr */ assert_ptr_equal(mbuf_output[0], mbuf_input[0]); /* check the port egress */ struct mrb_metadata * mrb_meta_output = mrbuf_cz_data(mbuf_output[0], MR_NODE_CTRLZONE_ID); assert_int_equal(mrb_meta_output->port_egress, 1); /* check the eth mac addr */ struct rte_ether_hdr * eth_hdr_output = rte_pktmbuf_mtod(mbuf_output[0], struct rte_ether_hdr *); assert_memory_equal(ð_hdr_output->dst_addr, &src_mac, sizeof(struct rte_ether_addr)); assert_memory_equal(ð_hdr_output->src_addr, &dst_mac, sizeof(struct rte_ether_addr)); /* check the ipv4 header */ uint32_t src_ip, dst_ip; inet_pton(AF_INET, "192.168.1.2", &src_ip); inet_pton(AF_INET, "192.168.1.1", &dst_ip); struct rte_ipv4_hdr * ipv4_hdr_output = (struct rte_ipv4_hdr *)(eth_hdr_output + 1); assert_int_equal(ipv4_hdr_output->src_addr, src_ip); assert_int_equal(ipv4_hdr_output->dst_addr, dst_ip); assert_int_equal(ipv4_hdr_output->time_to_live, 255); uint16_t output_checksum = ipv4_hdr_output->hdr_checksum; ipv4_hdr_output->hdr_checksum = 0; assert_int_equal(output_checksum, rte_ipv4_cksum(ipv4_hdr_output)); /* check the udp header */ struct rte_udp_hdr * udp_hdr_output = (struct rte_udp_hdr *)(ipv4_hdr_output + 1); assert_int_equal(udp_hdr_output->src_port, rte_cpu_to_be_16(3784)); assert_int_equal(udp_hdr_output->dst_port, rte_cpu_to_be_16(3784)); /* check the bfd header */ uint32_t discriminator_checker = 0, discriminator_remote = 0; struct bfd_hdr * bfd_hdr_output = (struct bfd_hdr *)(udp_hdr_output + 1); rte_memcpy(&discriminator_checker, bfd_hdr_output->your_discriminator, sizeof(uint32_t)); assert_int_equal(discriminator_checker, rte_cpu_to_be_32(discriminator_local)); rte_memcpy(&discriminator_checker, bfd_hdr_output->my_discriminator, sizeof(uint32_t)); assert_ptr_not_equal(discriminator_checker, 0); discriminator_remote = discriminator_checker; assert_int_equal(bfd_hdr_output->state, BFD_STATE_INIT); /* * 2. bfd init to up */ will_return(mock_pkt_input_process, 1); will_return(mock_pkt_input_process, mbuf_input); will_return(mock_pkt_output_process, mbuf_output); will_return(mock_pkt_output_process, &nr_mbuf_output); /* swap the eth mac addr */ struct rte_ether_addr swap_addr; rte_ether_addr_copy(ð_hdr_output->dst_addr, &swap_addr); rte_ether_addr_copy(ð_hdr_output->src_addr, ð_hdr_output->dst_addr); rte_ether_addr_copy(&swap_addr, ð_hdr_output->src_addr); /* swap ipv4_hdr */ uint32_t swap_ip = ipv4_hdr_output->src_addr; ipv4_hdr_output->src_addr = ipv4_hdr_output->dst_addr; ipv4_hdr_output->dst_addr = swap_ip; ipv4_hdr_output->time_to_live = 255; ipv4_hdr_output->hdr_checksum = rte_ipv4_cksum(ipv4_hdr_output); /* swap bfd discriminator */ uint32_t discriminator_swap = 0; rte_memcpy(&discriminator_swap, bfd_hdr_output->my_discriminator, sizeof(uint32_t)); rte_memcpy(bfd_hdr_output->my_discriminator, &bfd_hdr_output->your_discriminator, sizeof(uint32_t)); rte_memcpy(&bfd_hdr_output->your_discriminator, &discriminator_swap, sizeof(uint32_t)); bfd_hdr_output->state = BFD_STATE_UP; rte_graph_walk(graph_ptr); /* check the count */ assert_int_equal(nr_mbuf_output, 1); /* check the mbuf ptr */ assert_ptr_equal(mbuf_output[0], mbuf_input[0]); /* check the port egress */ mrb_meta_output = mrbuf_cz_data(mbuf_output[0], MR_NODE_CTRLZONE_ID); assert_int_equal(mrb_meta_output->port_egress, 1); /* check the eth mac addr */ assert_memory_equal(ð_hdr_output->dst_addr, &src_mac, sizeof(struct rte_ether_addr)); assert_memory_equal(ð_hdr_output->src_addr, &dst_mac, sizeof(struct rte_ether_addr)); /* check the ipv4 header */ assert_int_equal(ipv4_hdr_output->src_addr, src_ip); assert_int_equal(ipv4_hdr_output->dst_addr, dst_ip); assert_int_equal(ipv4_hdr_output->time_to_live, 255); output_checksum = ipv4_hdr_output->hdr_checksum; ipv4_hdr_output->hdr_checksum = 0; assert_int_equal(output_checksum, rte_ipv4_cksum(ipv4_hdr_output)); /* check the udp header */ assert_int_equal(udp_hdr_output->src_port, rte_cpu_to_be_16(3784)); assert_int_equal(udp_hdr_output->dst_port, rte_cpu_to_be_16(3784)); /* check the bfd header */ rte_memcpy(&discriminator_checker, bfd_hdr_output->your_discriminator, sizeof(uint32_t)); assert_int_equal(discriminator_checker, rte_cpu_to_be_32(discriminator_local)); rte_memcpy(&discriminator_checker, bfd_hdr_output->my_discriminator, sizeof(uint32_t)); assert_int_equal(discriminator_checker, discriminator_remote); assert_int_equal(bfd_hdr_output->state, BFD_STATE_UP); /* release the mbufs */ rte_pktmbuf_free_bulk(mbuf_output, 1); assert_true(rte_mempool_full(mock_pktmbuf_pool) == 1); } /* Test Case: bfd session full */ static void testcase_bfd_session_full(void ** state) { struct rte_graph * graph_ptr = rte_graph_lookup("test_bfd"); assert_non_null(graph_ptr); /* alloc the mbuf as input */ struct rte_mbuf * mbuf_input[1]; mbuf_input[0] = rte_pktmbuf_alloc(mock_pktmbuf_pool); assert_non_null(mbuf_input); /* set the return value for the mock function */ will_return(mock_pkt_input_process, 1); will_return(mock_pkt_input_process, mbuf_input); struct rte_mbuf * mbuf_output[1] = {}; 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); /* set mbuf pkt_len */ mbuf_input[0]->data_len = sizeof(struct rte_ether_hdr) + sizeof(struct rte_ipv4_hdr) + sizeof(struct rte_udp_hdr) + sizeof(struct bfd_hdr); mbuf_input[0]->pkt_len = mbuf_input[0]->data_len; /* prepare the bfd packet for initialization */ struct rte_ether_hdr * ether_hdr = rte_pktmbuf_mtod(mbuf_input[0], struct rte_ether_hdr *); struct rte_ipv4_hdr * ipv4_hdr = (struct rte_ipv4_hdr *)(ether_hdr + 1); struct rte_udp_hdr * udp_hdr = (struct rte_udp_hdr *)(ipv4_hdr + 1); struct bfd_hdr * bfd_hdr = (struct bfd_hdr *)(udp_hdr + 1); /* set the ether header */ eth_header_construct(ether_hdr, NULL, NULL, RTE_ETHER_TYPE_IPV4); /* set the ipv4 header */ ipv4_header_construct(ipv4_hdr, "172.16.1.1", NULL, IPPROTO_UDP, sizeof(struct rte_udp_hdr) + sizeof(struct bfd_hdr)); /* set the udp header */ udp_header_construct(udp_hdr, 3784, 3784, sizeof(struct bfd_hdr)); /* set the bfd header */ uint32_t discriminator_local = 0x12345678; bfd_header_construct(bfd_hdr, &discriminator_local, NULL, BFD_STATE_DOWN); /* set the metadata */ struct mrb_metadata * mrb_meta = mrbuf_cz_data(mbuf_input[0], MR_NODE_CTRLZONE_ID); mrb_metadata_clear(mrb_meta); mrb_meta->port_ingress = 1; /* prepare to parse the ingress pkt */ struct pkt_parser pkt_parser; pkt_parser_init(&pkt_parser, &mrb_meta->pkt_parser_result, LAYER_TYPE_ALL, MR_PKT_PARSER_LAYERS_MAX); pkt_parser_exec(&pkt_parser, mbuf_input[0]); /* simulate the scenario where the current BFD session handle is full */ struct bfd_test_main * bfd_test_main = *state; struct bfd_session_handle * bfd_session_handle = bfd_session_handle_get(bfd_test_main->bfd_node_main, 0); assert_non_null(bfd_session_handle); while (bfd_session_handle_is_full(bfd_session_handle) == 0) { bfd_session_add(bfd_session_handle, 1); } assert_int_equal(bfd_session_handle_is_full(bfd_session_handle), 1); /* run graph */ rte_graph_walk(graph_ptr); /* check the count */ assert_int_equal(nr_mbuf_drop, 1); /* check the mbuf ptr */ assert_ptr_equal(mbuf_drop[0], mbuf_input[0]); /* release the mbufs */ rte_pktmbuf_free_bulk(mbuf_drop, 1); assert_true(rte_mempool_full(mock_pktmbuf_pool) == 1); } /* Test Case: discriminator method flipping */ /* * BFD State Interaction Diagram * * A B * -------- -------- * DOWN DOWN * | | * | down->init | * |-----------------------------------| * | | * | | * | BFD DOWN | * |-------------------------> | * | | * | | * | BFD INIT | * |<------------------------- | * | | * | | * | BFD UP | * |-------------------------> | * | | * | | * | BFD UP | * |<------------------------- | * UP UP * * Legend: * - BFD DOWN: BFD Down state packet * - BFD INIT: BFD Init state packet * - BFD UP: BFD Up state packet * - XX->YY: State change from XX to YY */ static void testcase_bfd_discriminator_method_flipping(void ** state) { struct rte_graph * graph_ptr = rte_graph_lookup("test_bfd"); assert_non_null(graph_ptr); /* alloc the mbuf as input */ struct rte_mbuf * mbuf_input[1]; mbuf_input[0] = rte_pktmbuf_alloc(mock_pktmbuf_pool); assert_non_null(mbuf_input); /* set the return value for the mock function */ will_return(mock_pkt_input_process, 1); will_return(mock_pkt_input_process, mbuf_input); struct rte_mbuf * mbuf_output[1] = {}; unsigned int nr_mbuf_output = 0; will_return(mock_pkt_output_process, mbuf_output); will_return(mock_pkt_output_process, &nr_mbuf_output); /* set mbuf pkt_len */ mbuf_input[0]->data_len = sizeof(struct rte_ether_hdr) + sizeof(struct rte_ipv4_hdr) + sizeof(struct rte_udp_hdr) + sizeof(struct bfd_hdr); mbuf_input[0]->pkt_len = mbuf_input[0]->data_len; /* prepare the bfd packet for initialization */ struct rte_ether_hdr * ether_hdr = rte_pktmbuf_mtod(mbuf_input[0], struct rte_ether_hdr *); struct rte_ipv4_hdr * ipv4_hdr = (struct rte_ipv4_hdr *)(ether_hdr + 1); struct rte_udp_hdr * udp_hdr = (struct rte_udp_hdr *)(ipv4_hdr + 1); struct bfd_hdr * bfd_hdr = (struct bfd_hdr *)(udp_hdr + 1); /* * 1. bfd down to init */ /* set the ether header */ struct rte_ether_addr dst_mac = {.addr_bytes = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66}}; struct rte_ether_addr src_mac = {.addr_bytes = {0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff}}; eth_header_construct(ether_hdr, &src_mac, &dst_mac, RTE_ETHER_TYPE_IPV4); /* set the ipv4 header */ ipv4_header_construct(ipv4_hdr, NULL, NULL, IPPROTO_UDP, sizeof(struct rte_udp_hdr) + sizeof(struct bfd_hdr)); /* set the udp header */ udp_header_construct(udp_hdr, 3784, 3784, sizeof(struct bfd_hdr)); /* set the bfd header */ uint32_t discriminator_local = 0x12345678, discriminator_remote = 0x87654321; bfd_header_construct(bfd_hdr, &discriminator_local, &discriminator_remote, BFD_STATE_DOWN); struct mrb_metadata * mrb_meta = mrbuf_cz_data(mbuf_input[0], MR_NODE_CTRLZONE_ID); mrb_metadata_clear(mrb_meta); mrb_meta->port_ingress = 1; /* prepare to parse the ingress pkt */ struct pkt_parser pkt_parser; pkt_parser_init(&pkt_parser, &mrb_meta->pkt_parser_result, LAYER_TYPE_ALL, MR_PKT_PARSER_LAYERS_MAX); pkt_parser_exec(&pkt_parser, mbuf_input[0]); rte_graph_walk(graph_ptr); /* check the count */ assert_int_equal(nr_mbuf_output, 1); /* check the mbuf ptr */ assert_ptr_equal(mbuf_output[0], mbuf_input[0]); /* check the port egress */ struct mrb_metadata * mrb_meta_output = mrbuf_cz_data(mbuf_output[0], MR_NODE_CTRLZONE_ID); assert_int_equal(mrb_meta_output->port_egress, 1); /* check the eth mac addr */ struct rte_ether_hdr * eth_hdr_output = rte_pktmbuf_mtod(mbuf_output[0], struct rte_ether_hdr *); assert_memory_equal(ð_hdr_output->dst_addr, &src_mac, sizeof(struct rte_ether_addr)); assert_memory_equal(ð_hdr_output->src_addr, &dst_mac, sizeof(struct rte_ether_addr)); /* check the ipv4 header */ uint32_t src_ip, dst_ip; inet_pton(AF_INET, "192.168.1.2", &src_ip); inet_pton(AF_INET, "192.168.1.1", &dst_ip); struct rte_ipv4_hdr * ipv4_hdr_output = (struct rte_ipv4_hdr *)(eth_hdr_output + 1); assert_int_equal(ipv4_hdr_output->src_addr, src_ip); assert_int_equal(ipv4_hdr_output->dst_addr, dst_ip); assert_int_equal(ipv4_hdr_output->time_to_live, 255); uint16_t output_checksum = ipv4_hdr_output->hdr_checksum; ipv4_hdr_output->hdr_checksum = 0; assert_int_equal(output_checksum, rte_ipv4_cksum(ipv4_hdr_output)); /* check the udp header */ struct rte_udp_hdr * udp_hdr_output = (struct rte_udp_hdr *)(ipv4_hdr_output + 1); assert_int_equal(udp_hdr_output->src_port, rte_cpu_to_be_16(3784)); assert_int_equal(udp_hdr_output->dst_port, rte_cpu_to_be_16(3784)); /* check the bfd header */ uint32_t discriminator_checker = 0; struct bfd_hdr * bfd_hdr_output = (struct bfd_hdr *)(udp_hdr_output + 1); rte_memcpy(&discriminator_checker, bfd_hdr_output->your_discriminator, sizeof(uint32_t)); assert_int_equal(discriminator_checker, rte_cpu_to_be_32(discriminator_local)); rte_memcpy(&discriminator_checker, bfd_hdr_output->my_discriminator, sizeof(uint32_t)); assert_ptr_not_equal(discriminator_checker, rte_cpu_to_be_32(discriminator_remote)); assert_int_equal(bfd_hdr_output->state, BFD_STATE_INIT); /* * 2. bfd init to up */ will_return(mock_pkt_input_process, 1); will_return(mock_pkt_input_process, mbuf_input); will_return(mock_pkt_output_process, mbuf_output); will_return(mock_pkt_output_process, &nr_mbuf_output); /* swap the eth mac addr */ struct rte_ether_addr swap_addr; rte_ether_addr_copy(ð_hdr_output->dst_addr, &swap_addr); rte_ether_addr_copy(ð_hdr_output->src_addr, ð_hdr_output->dst_addr); rte_ether_addr_copy(&swap_addr, ð_hdr_output->src_addr); /* swap ipv4_hdr */ uint32_t swap_ip = ipv4_hdr_output->src_addr; ipv4_hdr_output->src_addr = ipv4_hdr_output->dst_addr; ipv4_hdr_output->dst_addr = swap_ip; ipv4_hdr_output->time_to_live = 255; ipv4_hdr_output->hdr_checksum = rte_ipv4_cksum(ipv4_hdr_output); /* swap bfd discriminator */ uint32_t discriminator_swap = 0; rte_memcpy(&discriminator_swap, bfd_hdr_output->my_discriminator, sizeof(uint32_t)); rte_memcpy(bfd_hdr_output->my_discriminator, &bfd_hdr_output->your_discriminator, sizeof(uint32_t)); rte_memcpy(&bfd_hdr_output->your_discriminator, &discriminator_swap, sizeof(uint32_t)); bfd_hdr_output->state = BFD_STATE_UP; rte_graph_walk(graph_ptr); /* check the count */ assert_int_equal(nr_mbuf_output, 1); /* check the mbuf ptr */ assert_ptr_equal(mbuf_output[0], mbuf_input[0]); /* check the port egress */ mrb_meta_output = mrbuf_cz_data(mbuf_output[0], MR_NODE_CTRLZONE_ID); assert_int_equal(mrb_meta_output->port_egress, 1); /* check the eth mac addr */ assert_memory_equal(ð_hdr_output->dst_addr, &src_mac, sizeof(struct rte_ether_addr)); assert_memory_equal(ð_hdr_output->src_addr, &dst_mac, sizeof(struct rte_ether_addr)); /* check the ipv4 header */ assert_int_equal(ipv4_hdr_output->src_addr, src_ip); assert_int_equal(ipv4_hdr_output->dst_addr, dst_ip); assert_int_equal(ipv4_hdr_output->time_to_live, 255); output_checksum = ipv4_hdr_output->hdr_checksum; ipv4_hdr_output->hdr_checksum = 0; assert_int_equal(output_checksum, rte_ipv4_cksum(ipv4_hdr_output)); /* check the udp header */ assert_int_equal(udp_hdr_output->src_port, rte_cpu_to_be_16(3784)); assert_int_equal(udp_hdr_output->dst_port, rte_cpu_to_be_16(3784)); /* check the bfd header */ rte_memcpy(&discriminator_checker, bfd_hdr_output->your_discriminator, sizeof(uint32_t)); assert_int_equal(discriminator_checker, rte_cpu_to_be_32(discriminator_local)); rte_memcpy(&discriminator_checker, bfd_hdr_output->my_discriminator, sizeof(uint32_t)); assert_ptr_not_equal(discriminator_checker, rte_cpu_to_be_32(discriminator_remote)); assert_int_equal(bfd_hdr_output->state, BFD_STATE_UP); /* release the mbufs */ rte_pktmbuf_free_bulk(mbuf_output, 1); assert_true(rte_mempool_full(mock_pktmbuf_pool) == 1); } int main(int argc, char * argv[]) { /* generate the eal args */ static char * eal_args[] = { "test_node_bfd", "-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"); } 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_bfd_node_main[] = { cmocka_unit_test(testcase_bfd_node_main_api_success), cmocka_unit_test(testcase_bfd_node_main_api_failure), }; const struct CMUnitTest group_bfd_session_handle[] = { cmocka_unit_test(testcase_bfd_session_handle_api_success), cmocka_unit_test(testcase_bfd_session_handle_api_failure), }; const struct CMUnitTest group_bfd_init[] = { cmocka_unit_test(testcase_bfd_init_success), cmocka_unit_test(testcase_bfd_deinit_success), }; const struct CMUnitTest group_bfd_discriminator_method_rfc[] = { cmocka_unit_test(testcase_bfd_rfc5881), cmocka_unit_test(testcase_bfd_session_full), }; const struct CMUnitTest group_bfd_discriminator_method_flipping[] = { cmocka_unit_test(testcase_bfd_discriminator_method_flipping), }; ret = cmocka_run_group_tests(group_bfd_node_main, NULL, NULL); ret += cmocka_run_group_tests(group_bfd_session_handle, NULL, NULL); ret += cmocka_run_group_tests(group_bfd_init, testgroup_bfd_init_setup, testgroup_bfd_init_teardown); ret += cmocka_run_group_tests(group_bfd_discriminator_method_rfc, testgroup_bfd_discriminator_method_rfc_setup, testgroup_bfd_discriminator_method_rfc_teardown); ret += cmocka_run_group_tests(group_bfd_discriminator_method_flipping, testgroup_bfd_discriminator_method_flipping_setup, testgroup_bfd_discriminator_method_flipping_teardown); rte_eal_cleanup(); return ret; }