/* * Copyright (c) 2014, 2018-2019 The Linux Foundation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials provided * with the distribution. * * Neither the name of The Linux Foundation nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #include "ipa_nat_test.h" #include "ipa_nat_map.h" #undef strcasesame #define strcasesame(x, y) \ (! strcasecmp((x), (y))) static inline const char* legal_mem_type( const char* mt ) { if ( strcasesame(mt, "DDR") ) return "DDR"; if ( strcasesame(mt, "SRAM") ) return "SRAM"; if ( strcasesame(mt, "HYBRID") ) return "HYBRID"; return NULL; } static int nat_rule_loop_check( ipa_table* table_ptr, uint32_t rule_hdl, void* record_ptr, uint16_t record_index, void* meta_record_ptr, uint16_t meta_record_index, void* arb_data_ptr ) { enum ipa3_nat_mem_in nmi; uint8_t is_expn_tbl; uint16_t rule_index; uint32_t tbl_hdl = (uint32_t) arb_data_ptr; struct ipa_nat_rule* rule_ptr = (struct ipa_nat_rule*) record_ptr; BREAK_RULE_HDL(table_ptr, rule_hdl, nmi, is_expn_tbl, rule_index); /* * By virtue of this function being called back by the walk, this * record_index is valid. Denote it as such in the map... */ if ( ipa_nat_map_add(MAP_NUM_99, record_index, 1) ) { IPAERR("ipa_nat_map_add(index(%u)) failed\n", record_index); return -EINVAL; } if ( rule_ptr->next_index == record_index ) { IPAERR("Infinite loop detected in IPv4 %s table, entry %u\n", (is_expn_tbl) ? "expansion" : "base", record_index); ipa_nat_dump_ipv4_table(tbl_hdl); return -EINVAL; } return 0; } static int nat_rule_validity_check( ipa_table* table_ptr, uint32_t rule_hdl, void* record_ptr, uint16_t record_index, void* meta_record_ptr, uint16_t meta_record_index, void* arb_data_ptr ) { enum ipa3_nat_mem_in nmi; uint8_t is_expn_tbl; uint16_t rule_index; uint16_t index; struct ipa_nat_rule* rule_ptr = (struct ipa_nat_rule*) record_ptr; BREAK_RULE_HDL(table_ptr, rule_hdl, nmi, is_expn_tbl, rule_index); index = rule_ptr->next_index; if ( index && ipa_nat_map_find(MAP_NUM_99, index, NULL) ) { IPAERR("Invalid next index %u found in IPv4 %s table entry %u\n", index, (is_expn_tbl) ? "expansion" : "base", rule_index); return -EINVAL; } if ( is_expn_tbl ) { index = rule_ptr->prev_index; if ( index && ipa_nat_map_find(MAP_NUM_99, index, NULL) ) { IPAERR("Invalid previous index %u found in IPv4 %s table entry %u\n", index, "expansion", rule_index); return -EINVAL; } } return 0; } static int index_loop_check( ipa_table* table_ptr, uint32_t rule_hdl, void* record_ptr, uint16_t record_index, void* meta_record_ptr, uint16_t meta_record_index, void* arb_data_ptr ) { enum ipa3_nat_mem_in nmi; uint8_t is_expn_tbl; uint16_t rule_index; uint32_t tbl_hdl = (uint32_t) arb_data_ptr; struct ipa_nat_indx_tbl_rule* itr_ptr = (struct ipa_nat_indx_tbl_rule*) record_ptr; BREAK_RULE_HDL(table_ptr, rule_hdl, nmi, is_expn_tbl, rule_index); /* * By virtue of this function being called back by the walk, this * record_index is valid. Denote it as such in the map... */ if ( ipa_nat_map_add(MAP_NUM_99, record_index, 1) ) { IPAERR("ipa_nat_map_add(index(%u)) failed\n", record_index); return -EINVAL; } if ( itr_ptr->next_index == record_index ) { IPAERR("Infinite loop detected in IPv4 index %s table, entry %u\n", (is_expn_tbl) ? "expansion" : "base", record_index); ipa_nat_dump_ipv4_table(tbl_hdl); return -EINVAL; } return 0; } static int index_validity_check( ipa_table* table_ptr, uint32_t rule_hdl, void* record_ptr, uint16_t record_index, void* meta_record_ptr, uint16_t meta_record_index, void* arb_data_ptr ) { enum ipa3_nat_mem_in nmi; uint8_t is_expn_tbl; uint16_t rule_index; uint16_t index; struct ipa_nat_indx_tbl_rule* itr_ptr = (struct ipa_nat_indx_tbl_rule*) record_ptr; BREAK_RULE_HDL(table_ptr, rule_hdl, nmi, is_expn_tbl, rule_index); index = itr_ptr->next_index; if ( index && ipa_nat_map_find(MAP_NUM_99, index, NULL) ) { IPAERR("Invalid next index %u found in IPv4 index %s table entry %u\n", index, (is_expn_tbl) ? "expansion" : "base", rule_index); return -EINVAL; } if ( is_expn_tbl ) { struct ipa_nat_indx_tbl_meta_info* mi_ptr = meta_record_ptr; if ( ! mi_ptr ) { IPAERR("Missing meta pointer for IPv4 index %s table entry %u\n", "expansion", rule_index); return -EINVAL; } index = mi_ptr->prev_index; if ( index && ipa_nat_map_find(MAP_NUM_99, index, NULL) ) { IPAERR("Invalid previous index %u found in IPv4 index %s table entry %u\n", index, "expansion", rule_index); return -EINVAL; } } return 0; } int ipa_nat_validate_ipv4_table( u32 tbl_hdl ) { int ret; /* * Map MAP_NUM_99 will be used to keep, and to check for, * record validity. * * The first walk will fill it. The second walk will use it... */ ipa_nat_map_clear(MAP_NUM_99); IPADBG("Checking IPv4 active rules:\n"); ret = ipa_nati_walk_ipv4_tbl(tbl_hdl, USE_NAT_TABLE, nat_rule_loop_check, tbl_hdl); if ( ret != 0 ) { return ret; } ret = ipa_nati_walk_ipv4_tbl(tbl_hdl, USE_NAT_TABLE, nat_rule_validity_check, 0); if ( ret != 0 ) { return ret; } /* * Map MAP_NUM_99 will be used to keep, and to check for, * record validity. * * The first walk will fill it. The second walk will use it... */ ipa_nat_map_clear(MAP_NUM_99); IPADBG("Checking IPv4 index active rules:\n"); ret = ipa_nati_walk_ipv4_tbl(tbl_hdl, USE_INDEX_TABLE, index_loop_check, tbl_hdl); if ( ret != 0 ) { return ret; } ret = ipa_nati_walk_ipv4_tbl(tbl_hdl, USE_INDEX_TABLE, index_validity_check, 0); if ( ret != 0 ) { return ret; } return 0; } static void _dispUsage( const char* progNamePtr ) { printf( "Usage: %s [-d -r N -i N -e N -m mt]\n" "Where:\n" " -d Each test is discrete (create table, add rules, destroy table)\n" " If not specified, only one table create and destroy for all tests\n" " -r N Where N is the number of times to run the inotify regression test\n" " -i N Where N is the number of times (iterations) to run test\n" " -e N Where N is the number of entries in the NAT\n" " -m mt Where mt is the type of memory to use for the NAT\n" " Legal mt's: DDR, SRAM, or HYBRID (ie. use SRAM and DDR)\n" " -g M-N Run tests M through N only\n", progNamePtr); fflush(stdout); } static NatTests nt_array[] = { NAT_TEST_ENTRY(ipa_nat_test000, 1, 0), NAT_TEST_ENTRY(ipa_nat_test001, 1, 0), NAT_TEST_ENTRY(ipa_nat_test002, 1, 0), NAT_TEST_ENTRY(ipa_nat_test003, 1, 0), NAT_TEST_ENTRY(ipa_nat_test004, 1, 0), NAT_TEST_ENTRY(ipa_nat_test005, 1, 0), NAT_TEST_ENTRY(ipa_nat_test006, 1, 0), NAT_TEST_ENTRY(ipa_nat_test007, 1, 0), NAT_TEST_ENTRY(ipa_nat_test008, 1, 0), NAT_TEST_ENTRY(ipa_nat_test009, 1, 0), NAT_TEST_ENTRY(ipa_nat_test010, IPA_NAT_TEST_PRE_COND_TE, 0), NAT_TEST_ENTRY(ipa_nat_test011, IPA_NAT_TEST_PRE_COND_TE, 0), NAT_TEST_ENTRY(ipa_nat_test012, IPA_NAT_TEST_PRE_COND_TE, 0), NAT_TEST_ENTRY(ipa_nat_test013, IPA_NAT_TEST_PRE_COND_TE, 0), NAT_TEST_ENTRY(ipa_nat_test014, IPA_NAT_TEST_PRE_COND_TE, 0), NAT_TEST_ENTRY(ipa_nat_test015, IPA_NAT_TEST_PRE_COND_TE, 0), NAT_TEST_ENTRY(ipa_nat_test016, IPA_NAT_TEST_PRE_COND_TE, 0), NAT_TEST_ENTRY(ipa_nat_test017, IPA_NAT_TEST_PRE_COND_TE, 0), NAT_TEST_ENTRY(ipa_nat_test018, IPA_NAT_TEST_PRE_COND_TE, 0), NAT_TEST_ENTRY(ipa_nat_test019, IPA_NAT_TEST_PRE_COND_TE, 0), NAT_TEST_ENTRY(ipa_nat_test020, IPA_NAT_TEST_PRE_COND_TE, 0), NAT_TEST_ENTRY(ipa_nat_test021, IPA_NAT_TEST_PRE_COND_TE, 0), NAT_TEST_ENTRY(ipa_nat_test022, IPA_NAT_TEST_PRE_COND_TE, 0), NAT_TEST_ENTRY(ipa_nat_test023, IPA_NAT_TEST_PRE_COND_TE, 0), NAT_TEST_ENTRY(ipa_nat_test024, IPA_NAT_TEST_PRE_COND_TE, 0), NAT_TEST_ENTRY(ipa_nat_test025, IPA_NAT_TEST_PRE_COND_TE, 0), /* * Add new tests just above this comment. Keep the following two * at the end... */ NAT_TEST_ENTRY(ipa_nat_test999, 1, 0), NAT_TEST_ENTRY(ipa_nat_testREG, 1, 0), }; int main( int argc, char* argv[] ) { int sep = 0; int ireg = 0; uint32_t nt = 1; int total_ents = 100; uint32_t ht = 0; uint32_t start = 0, end = 0; char* nat_mem_type = "DDR"; uint32_t tbl_hdl = 0; uint32_t pub_ip_addr; uint32_t i, ub, cnt, exec, pass; void* adp; time_t t; int c, ret; IPADBG("Testing user space nat driver\n"); while ( (c = getopt(argc, argv, "dr:i:e:m:h:g:?")) != -1 ) { switch (c) { case 'd': sep = 1; break; case 'r': ireg = atoi(optarg); break; case 'i': nt = atoi(optarg); break; case 'e': total_ents = atoi(optarg); break; case 'm': if ( ! (nat_mem_type = legal_mem_type(optarg)) ) { fprintf(stderr, "Illegal: -m %s\n", optarg); _dispUsage(basename(argv[0])); exit(0); } break; case 'h': ht = atoi(optarg); break; case 'g': if ( sscanf(optarg, "%u-%u", &start, &end) != 2 || ( start >= end || end >= array_sz(nt_array) - 1 ) ) { fprintf(stderr, "Illegal: -f %s\n", optarg); _dispUsage(basename(argv[0])); exit(0); } break; case '?': default: _dispUsage(basename(argv[0])); exit(0); break; } } srand(time(&t)); pub_ip_addr = RAN_ADDR; exec = pass = 0; for ( cnt = ret = 0; cnt < nt && ret == 0; cnt++ ) { IPADBG("ITERATION [%u] OF TESING\n", cnt + 1); if ( ireg ) { adp = &ireg; i = array_sz(nt_array) - 1; ub = array_sz(nt_array); } else { adp = &tbl_hdl; i = ( end ) ? start : 0; ub = ( end ) ? end : array_sz(nt_array) - 1; if ( i != 0 && ! sep ) { ipa_nat_test000( nat_mem_type, pub_ip_addr, total_ents, tbl_hdl, 0, adp); } } for ( ; i < ub && ret == 0; i++ ) { if ( total_ents >= nt_array[i].num_ents_trigger ) { IPADBG("+------------------------------------------------+\n"); IPADBG("| Executing test: %s |\n", nt_array[i].func_name); IPADBG("+------------------------------------------------+\n"); ret = nt_array[i].func( nat_mem_type, pub_ip_addr, total_ents, tbl_hdl, sep, adp); exec++; if ( ret == 0 ) { IPADBG("<<<<< Test %s SUCCEEDED >>>>>\n", nt_array[i].func_name); pass++; if ( ht || nt_array[i].test_hold_time_in_secs ) { ht = (ht) ? ht : nt_array[i].test_hold_time_in_secs; sleep(ht); } } else { IPAERR("<<<<< Test %s FAILED >>>>>\n", nt_array[i].func_name); } } } } if ( ret && tbl_hdl ) { ipa_nat_test999( nat_mem_type, pub_ip_addr, total_ents, tbl_hdl, 0, &tbl_hdl); } IPADBG("Total NAT Tests Run:%u, Pass:%u, Fail:%u\n", exec, pass, exec - pass); return 0; }