blob: 340ee48506b90d8ffb14eed209564f8bbc08842a [file] [log] [blame]
/*
* 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 <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>
#include <unistd.h>
#include <libgen.h>
#include <string.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#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;
}