/* ** Copyright (C) 2001-2006 by Carnegie Mellon University. ** ** @OPENSOURCE_HEADER_START@ ** ** Use of the SILK system and related source code is subject to the terms ** of the following licenses: ** ** GNU Public License (GPL) Rights pursuant to Version 2, June 1991 ** Government Purpose License Rights (GPLR) pursuant to DFARS 252.225-7013 ** ** NO WARRANTY ** ** ANY INFORMATION, MATERIALS, SERVICES, INTELLECTUAL PROPERTY OR OTHER ** PROPERTY OR RIGHTS GRANTED OR PROVIDED BY CARNEGIE MELLON UNIVERSITY ** PURSUANT TO THIS LICENSE (HEREINAFTER THE "DELIVERABLES") ARE ON AN ** "AS-IS" BASIS. CARNEGIE MELLON UNIVERSITY MAKES NO WARRANTIES OF ANY ** KIND, EITHER EXPRESS OR IMPLIED AS TO ANY MATTER INCLUDING, BUT NOT ** LIMITED TO, WARRANTY OF FITNESS FOR A PARTICULAR PURPOSE, ** MERCHANTABILITY, INFORMATIONAL CONTENT, NONINFRINGEMENT, OR ERROR-FREE ** OPERATION. CARNEGIE MELLON UNIVERSITY SHALL NOT BE LIABLE FOR INDIRECT, ** SPECIAL OR CONSEQUENTIAL DAMAGES, SUCH AS LOSS OF PROFITS OR INABILITY ** TO USE SAID INTELLECTUAL PROPERTY, UNDER THIS LICENSE, REGARDLESS OF ** WHETHER SUCH PARTY WAS AWARE OF THE POSSIBILITY OF SUCH DAMAGES. ** LICENSEE AGREES THAT IT WILL NOT MAKE ANY WARRANTY ON BEHALF OF ** CARNEGIE MELLON UNIVERSITY, EXPRESS OR IMPLIED, TO ANY PERSON ** CONCERNING THE APPLICATION OF OR THE RESULTS TO BE OBTAINED WITH THE ** DELIVERABLES UNDER THIS LICENSE. ** ** Licensee hereby agrees to defend, indemnify, and hold harmless Carnegie ** Mellon University, its trustees, officers, employees, and agents from ** all claims or demands made against them (and any related losses, ** expenses, or attorney's fees) arising out of, or relating to Licensee's ** and/or its sub licensees' negligent use or willful misuse of or ** negligent conduct or willful misconduct regarding the Software, ** facilities, or other rights or assistance granted by Carnegie Mellon ** University under this License, including, but not limited to, any ** claims of product liability, personal injury, death, damage to ** property, or violation of any laws or regulations. ** ** Carnegie Mellon University Software Engineering Institute authored ** documents are sponsored by the U.S. Department of Defense under ** Contract F19628-00-C-0003. Carnegie Mellon University retains ** copyrights in all material produced under this contract. The U.S. ** Government retains a non-exclusive, royalty-free license to publish or ** reproduce these documents, or allow others to do so, for U.S. ** Government purposes only pursuant to the copyright license under the ** contract clause at 252.227.7013. ** ** @OPENSOURCE_HEADER_END@ */ /* File: hashlib_tests.c: regression testing application for the hash library * * There's room to improve this to make the testing more thorough. */ #include "silk.h" RCSIDENT("$SiLK: hashlib_tests.c 5620 2006-11-09 21:41:03Z mthomas $"); #include #include #include /* Make sure the endianness is defined */ #include "hashlib_conf.h" #include "rwpack.h" /* Never define the integer types since they're already defined when * we include rwpack.h */ #undef DEFINE_INT_TYPES #include "hashlib.h" #include "hashwrap.h" /* Make an IP address. Used by tuple_test */ #define mkip(a,b,c,d) (a)<<24|(b)<<16|(c)<<8|(d) /* Run a simple load test using ip counter. Data is not verified. */ static void ipctr_load_test(void) { uint32_t max_key = (uint32_t) ((1<<20) * 0.74); uint32_t estimated_max_key = (1<<18); uint32_t i; uint32_t key; IpCounter *table_ptr = ipctr_create_counter(estimated_max_key); fprintf(stdout, "\n---- Running ip counter load test.\n"); /* Count random keys */ for (i=0;i_data)); sip = dip = sp = dp = proto = count = 0; while (tuplectr_iterate(table_ptr, &iter, &sip, &dip, &sp, &dp, &proto, &count) == OK) { for (i = 0; i < 2; i++) { if (sip == rw[i].sIP.ipnum && dip == rw[i].dIP.ipnum) { printf("found rw2[%d]...",i); if (count == rw2count[i]) { printf ("PASSED\n"); } else { printf ("FAILED got %d expected %d\n",count,rw2count[i]); exit(0); } } } } /* all done */ tuplectr_free(table_ptr); } /*********** Statistics based on 5-tuples *******************/ static void tuplestats_test(void) { rwRec rw[5]; int i,rv; char *tmpStr; char *tmpStr2; void **slot; TupleStats *table_ptr; /* -------------------- RWREC SETUP */ rw[0].sIP.ipnum = mkip(10,7,11,10); rw[0].dIP.ipnum = mkip(10,7,11,9); rw[0].sPort = 10001; rw[0].dPort = 80; rw[0].proto = 6; rw[1].sIP.ipnum = mkip(10,1,10,3); rw[1].dIP.ipnum = mkip(10,1,10,2); rw[1].sPort = 10002; rw[1].dPort = 80; rw[1].proto = 6; rw[2].sIP.ipnum = mkip(10,7,11,10); rw[2].dIP.ipnum = mkip(10,7,11,9); rw[2].sPort = 10003; rw[2].dPort = 57; rw[2].proto = 17; rw[3].sIP.ipnum = mkip(10,7,11,10); rw[3].dIP.ipnum = mkip(10,7,11,9); rw[3].sPort = 10004; rw[3].dPort = 25; rw[3].proto = 6; rw[4].sIP.ipnum = mkip(10,1,10,3); rw[4].dIP.ipnum = mkip(10,1,10,2); rw[4].sPort = 10005; rw[4].dPort = 443; rw[4].proto = 6; /* -------------------- INSERTION */ printf("\n---- Testing tuple statistics table\n"); table_ptr = tuplestats_create_table(FIELD_ALL, 5); for (i = 0; i < 5; i++) { tmpStr = malloc(80); snprintf(tmpStr,80,"0x%08x:%05d => 0x%08x:%05d (%d)", rw[i].sIP.ipnum,rw[i].sPort,rw[i].dIP.ipnum,rw[i].dPort, rw[i].proto); tuplestats_rec_insert(table_ptr, &rw[i], &slot); *slot = tmpStr; } /* -------------------- LOOKUP */ for (i = 0; i < 5; i++) { tmpStr = malloc(80); snprintf(tmpStr,80,"0x%08x:%05d => 0x%08x:%05d (%d)", rw[i].sIP.ipnum,rw[i].sPort,rw[i].dIP.ipnum,rw[i].dPort, rw[i].proto); printf("checking rw[%d]...",i); rv = tuplestats_rec_lookup(table_ptr, &rw[i], (void **)&tmpStr2); if (rv < 0) { printf("FAILED bad return %d\n",rv); exit(0); } else if (strcmp(tmpStr,tmpStr2) == 0) { printf("PASSED\n"); } else { printf("FAILED got %s expected %s\n",tmpStr2,tmpStr); exit(0); } free(tmpStr); free(tmpStr2); } tuplestats_free(table_ptr); } /*********** Statistics based on IP addresses *******************/ void ipstats_test(void) { IpStats *table_ptr; uint32_t iKey; const uint32_t max_key = 10; const int initial_size = 40; char val_str[255]; char **str_pptr; char *str_ptr; int passed = 1; HASH_ITER iter; int rv; fprintf(stdout, "\n---- Testing ip statistics table\n"); /* Create the statitistics table */ table_ptr = ipstats_create_table(initial_size); assert(table_ptr); printf("Inserting entries...\n"); /* Add entries */ for (iKey=0;iKey<=max_key;iKey++) { sprintf(val_str, "%d", iKey); str_pptr = NULL; ipstats_insert(table_ptr, iKey, (void ***) &str_pptr); *str_pptr = strdup(val_str); /* Update the entry with string '- updated' */ str_pptr = NULL; ipstats_insert(table_ptr, iKey, (void ***) &str_pptr); sprintf(val_str, "%s - updated", *str_pptr); *str_pptr = strdup(val_str); } printf("Testing lookup...\n"); for (iKey=0;iKey %s ", iKey, str_ptr); printf("****Incorrect value! ****\n"); exit(0); passed = 0; } } /* Never reached for now */ if (passed) printf("Lookup test PASSED.\n"); else printf("****Lookup test FAILED.\n"); printf("Testing iteration\n"); iter = ipstats_create_iterator(table_ptr); while (ipstats_iterate(table_ptr, &iter, &iKey, (void **) &str_ptr) != ERR_NOMOREENTRIES) { /* Create comparison string */ sprintf(val_str, "%d - updated", iKey); /* Do comparison */ if (strcmp(val_str, str_ptr) != 0) { printf("%d --> %s ", iKey, str_ptr); printf("****Incorrect value! ****\n"); passed = 0; exit(0); } } if (passed) printf("Iteration test PASSED.\n"); else printf("****Iteration test FAILED.\n"); printf("Cleaning up\n"); ipstats_free(table_ptr); return; } void ipctr_test(void) { IpCounter *counter_ptr; const uint32_t max_key = 100; uint32_t j; HASH_ITER iter; uint32_t key; uint32_t val; int succeeded = 1; int rv; counter_ptr = ipctr_create_counter( max_key*2); fprintf(stdout, "\n---- Testing ip-based counting\n"); assert(counter_ptr); /* Testing -- For each key i, increment i times */ for (key=1;key<=max_key;key++) { for (j=0;j 0x%08x/24",hcn[i].host,hcn[i].net); hcnstats_insert(table_ptr, hcn[i].host, hcn[i].net, &slot); *slot = tmpStr; } for (i = 0; i < 5; i++) { tmpStr = malloc(80); snprintf(tmpStr,80,"0x%08x => 0x%08x/24",hcn[i].host,hcn[i].net); printf("checking hcn[%d]...",i); rv = hcnstats_lookup(table_ptr, hcn[i].host, hcn[i].net, (void **)&tmpStr2); if (rv < 0) { printf("FAILED bad return %d\n",rv); exit(0); } else if (strcmp(tmpStr,tmpStr2) == 0) { printf("PASSED\n"); } else { printf("FAILED got %s expected %s\n",tmpStr2,tmpStr); exit(0); } free(tmpStr); free(tmpStr2); } hcnstats_free(table_ptr); } static void hashlib_test1(void) { int passed = 1; uint32_t iKey; uint32_t iValue; uint32_t *key_ref, *val_ref; const uint32_t max_key = 400000; const int initial_table_size = 600000; HashTable *test_ptr = NULL; uint32_t no_value = 0xFFFFFFFF; uint8_t *no_value_ptr = (uint8_t*) malloc(sizeof(iValue)); uint32_t num_found = 0; HASH_ITER iter; int rv; printf("\n--- Testing value-based hash table\n"); /* Allocate memory for and initialize special "empty" value */ no_value_ptr = (uint8_t*) malloc(sizeof(iValue)); memcpy(no_value_ptr, &no_value, sizeof(iValue)); /* Create a table to test with */ test_ptr = hashlib_create_table(sizeof(iKey), sizeof(iValue), HTT_INPLACE, /* values, not pointers */ no_value_ptr, /* all FF means empty */ NULL, 0, /* No user data */ initial_table_size, DEFAULT_LOAD_FACTOR); assert(test_ptr); /* Populate the table with integers and their doubles */ for (iKey=1;iKey<=max_key;iKey++) { iValue = iKey*2; hashlib_insert(test_ptr, (uint8_t*) &iKey, (uint8_t**) &val_ref); memcpy(val_ref, &iValue, sizeof(iValue)); } /* Validate num entries */ if (hashlib_count_entries(test_ptr) != max_key) { printf(("Error in hashlib_test1." " hashlib_count_entries returned incorrect value\n")); passed = 0; exit(0); } /* Serialize it to and from disk */ printf("Saving table:\n"); hashlib_dump_table_header(stderr, test_ptr); rv = hashlib_save_table(test_ptr, "test.dat", NULL, 0); assert(rv==OK); hashlib_free_table(test_ptr); test_ptr = NULL; printf("Restoring table:\n"); rv = hashlib_restore_table(&test_ptr, "test.dat", NULL, 0); assert(rv==OK); hashlib_dump_table_header(stderr, test_ptr); assert(rv==OK); printf("Testing iteration\n"); num_found = 0; iter = hashlib_create_iterator(test_ptr); while (hashlib_iterate(test_ptr, &iter, (uint8_t**) &key_ref, (uint8_t**) &val_ref) != ERR_NOMOREENTRIES) { uint32_t inv_val = (uint32_t) (*val_ref)/2; num_found++; if (inv_val != *key_ref) { printf("%u --> %u (%u)", *key_ref, *val_ref, inv_val); printf("****Incorrect value: %u != %u\n", inv_val, *key_ref); passed = 0; exit(0); } } if (num_found != max_key) { printf("Iteration failed. Expected %d entries, found %d\n", max_key, num_found); passed=0; exit(0); } if (passed) printf("Iteration test PASSED.\n"); else printf("****Iteration test FAILED.\n"); printf("Testing lookup\n"); for (iKey=1;iKey<=max_key;iKey++) { uint32_t inv_val; key_ref = &iKey; iValue = iKey*2; hashlib_lookup(test_ptr, (uint8_t*) &iKey, (uint8_t**) &val_ref); inv_val = (*val_ref)/2; if (inv_val != *key_ref) { printf("%u --> %u (%u)", *key_ref, *val_ref, inv_val); printf("****Incorrect value: %u != %u\n", inv_val, *key_ref); passed = 0; exit(0); } } if (passed) printf("Lookup test PASSED.\n"); else printf("****Lookup test FAILED.\n"); hashlib_free_table(test_ptr); } /* NOTE: remove is not implemented. We may implement it * eventually. Remove is intrinsically expensive since it requires a * rehash. */ #if 0 static void hashlib_test_remove(void) { HashTable *table_ptr; uint8_t *val_ptr; int i, j; int rv; uint32_t key; uint32_t removed_keys[] = { 152, /* -> 62 */ 27, /* -> 62 */ 7 /* -> 62 */ }; uint32_t num_present = 0; uint32_t present_keys[300-sizeof(removed_keys)/4]; int num_removed_keys = sizeof(removed_keys)/4; table_ptr = hashlib_create_table(sizeof(uint32_t), sizeof(uint32_t), HTT_INPLACE, /* values, not pointers */ 0, /* 0 value is empty */ NULL, 0, /* No user data */ 300, DEFAULT_LOAD_FACTOR); /* Add values except those in removed_keys to hash table and * to present_keys array */ for (i=0;i<300;i++) { uint8_t use_it_bool = 1; /* Add it to present vals only if we're not going to remove it */ for (j=0;j